悬赏一关注:状压写法求调(带注释)
查看原帖
悬赏一关注:状压写法求调(带注释)
398310
hundunqidian楼主2023/8/2 12:17

不能通过样例,检查1小时没能查出问题……

/*
dp[h][s]表示前h层树,包含点的集合为s
dp[h][s]=min(dp[h-1][s去掉r]+cost(s去掉r,r)*h)
cost(s^r,r):r集合中每个点到s^r的最短距离和
*/
#include<bits/stdc++.h>
#define int long long 
using namespace std;
int c[(1<<12)][(1<<12)],cost[(1<<13)][13],d[15][15];
int n,m,u,v,w;
int lowbit(int s){
	return s&(-s);
}
int lg2[(1<<13)],f[15][(1<<13)];
signed main(){
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	memset(d,0x3f,sizeof(d)); //初始化边权极大值 
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		cin>>u>>v>>w;
		u--; v--; 
		d[u][v]=d[v][u]=w;
	}
	for(int i=0;i<=n;i++){
		lg2[(1<<i)]=i;
	}
	for(int i=0;i<n;i++){
		//c[s][i]:点i到集合s的最短边 
		c[0][i]=1e10;
		for(int s=1;s<(1<<n);s++){
			int k=lowbit(s); //lg2[k]为s集合中最小的元素 
			c[s][i]=min(c[s^k][i],d[lg2[k]][i]); 
			//此处是递推,因为k是最小元素,c[s^k]一定已经处理了 
		}
	} 
	for(int r=1;r<(1<<n);r++){
		//cost[s][r]:r集合每个点到s的最短边之和 
		int k=lowbit(r);
		for(int s=0;s<(1<<n);s++){
			cost[s][r]=cost[s][r^k]+c[s][lg2[k]]; 
		}
	}
	for(int s=0;s<(1<<n);s++){
		f[0][s]=1e10; //赋初值极大值 
	}
	for(int i=0;i<n;i++){
		f[0][(1<<n)]=0; //枚举根 
	}
	for(int h=1;h<n;h++){
		for(int s=1;s<(1<<n);s++){
			f[h][s]=1e10;
			for(int r=s;r!=0;r=(r-1)&s){
				if(cost[s^r][r]==1e10) continue;
				f[h][s]=min(f[h][s],f[h-1][s^r]+cost[s^r][r]*h);
			}
		}
	} 
	int ans=1e10;
	for(int i=0;i<n;i++){
		ans=min(ans,f[i][(1<<n)-1]);
	}
	cout<<ans<<'\n';
	return 0;
}
//感谢.JPG
2023/8/2 12:17
加载中...