关于这题怎么拿暴力分
查看原帖
关于这题怎么拿暴力分
777081
Geoyster楼主2023/10/28 21:47

正解固然好,但是平凡的我没想到,只想了一个 O(n22n)\mathcal{O}(n^22^n) 的暴力,请问各位有无更好的暴力写法?

我的做法是构造一个特殊点 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;
}
2023/10/28 21:47
加载中...