正解固然好,但是平凡的我没想到,只想了一个 O(n22n) 的暴力,请问各位有无更好的暴力写法?
我的做法是构造一个特殊点 0,然后将它与所有叶子节点以 1 为边权相连,树上边权为两个端点子树大小的差,这样状压算一下经过所有点的从 0 到 0 的最短回路即为答案。
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<int,int>;
const int N = 15 + 1;
int n;
struct edge{
int n,v,w;
}g[N<<1];
int h[N];
ll dp[N][1<<N];
int deg[N],sub[N];
void add(int u,int v,int w=1){
static int tot=1;
g[++tot].n=h[u];
h[u]=tot;
g[tot].v=v;
g[tot].w=w;
}
void dfs(int u,int pre){
sub[u]=1;
for(int i=h[u];i;i=g[i].n){
int v=g[i].v;
if(v!=pre){
dfs(v,u);
sub[u]+=sub[v];
}
}
for(int i=h[u];i;i=g[i].n){
int v=g[i].v;
if(v!=pre){
g[i].w=g[i^1].w=sub[u]-sub[v];
}
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n;
for(int i=2;i<=n;i++){
int o; cin>>o;
add(o,i); add(i,o);
deg[o]++; deg[i]++;
}
dfs(1,0);
for(int i=2;i<=n;i++){
if(deg[i]==1){
add(0,i,1); add(i,0,1);
}
}
int mask=1<<(n+1); mask--;
queue<pii> q;
q.push(make_pair(0,1));
memset(dp,0x3f,sizeof dp);
dp[0][1]=0;
while(!q.empty()){
int u=q.front().first;
int state=q.front().second;
q.pop();
if(state==mask&&u==0) continue;
for(int i=h[u];i;i=g[i].n){
int v=g[i].v,w=g[i].w;
int now=state|(1<<v);
if(dp[v][now]>dp[u][state]+w){
dp[v][now]=dp[u][state]+w;
q.push(make_pair(v,now));
}
}
}
cout<<dp[0][mask];
return 0;
}