版权声明:蒟蒻Blog随意转载 https://blog.csdn.net/a1799342217/article/details/82632551
状压DP
为什么我会觉得prim是对的!为什么我70分的暴力都不打!果然我好菜
我是不会告诉你我不知道怎么枚子集的
n=12就是状压的范围。据说标算
我不会啊,优化过的
我也不会啊,我只会
啊不管了能过就行!
Orz写模拟退火的
表示以 为根的子树中, 的深度的为 ,子树中的节点集合为 的最小代价。那么有 ,其中 是 的子集, 为 内的一个点。时间复杂度为 。
把转移方程中与 无关的提取出来,预处理 ,这样就是 的了。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 15
#define M (1<<12)+1
using namespace std;
int n,m,ans=1e9,a[N][N],f[N][N][M],g[N][N][M];
int main(){
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++){
a[i][j]=1e9;
for (int s=1;s<1<<n;s++)
if (s!=1<<i-1) f[i][j][s]=g[i][j][s]=1e9;
}
for (int i=1,x,y,z;i<=m;i++)
scanf("%d%d%d",&x,&y,&z),a[x][y]=a[y][x]=min(a[x][y],z);
for (int j=n-1;j;j--)
for (int i=1;i<=n;i++)
for (int s=1;s<1<<n;s++){
for (int k=1;k<=n;k++)
if (((1<<k-1)&s)&&a[i][k]!=1e9)
g[i][j][s]=min(g[i][j][s],f[k][j+1][s]+a[i][k]*j);
for (int ss=s&s-1;ss;ss=ss-1&s)
f[i][j][s]=min(f[i][j][s],f[i][j][s^ss]+g[i][j][ss]);
}
for (int i=1;i<=n;i++) ans=min(ans,f[i][1][(1<<n)-1]);
return printf("%d\n",ans),0;
}