[题解]宝藏(状压

时间:2019-10-10
本文章向大家介绍[题解]宝藏(状压,主要包括[题解]宝藏(状压使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

数据范围小,不是爆搜就是状压

发现每个集合s不能表示所有状态,还有一个状态是和起始点的距离,这样我们直接用$f[x][s][d]$表示点x在点集s深度为d的最小代价,暴力枚举每个起始点直接扩展状态,把s跑满就更新答案,图上所以dfs实现还好写

#include<bits/stdc++.h>
#define ll long long 
using namespace std;
const int inf=1e9+7;
const int maxn=15;
int n,m,g[maxn][maxn],ans=inf,lim;
int dis[maxn],f[maxn][1<<maxn][maxn];//x在点集s中深度为k的最小代价 
inline void dfs(int s,int sum,int dep){
    if(sum>=ans)return;
    if(s==lim){ans=sum;return;}
    for(int i=1;i<=n;i++){
        if(!(1<<(i-1)&s))continue;
        for(int j=1;j<=n;j++)
        if(!(1<<(j-1)&s)&&g[i][j]!=0x3f3f3f3f)//没有选过j且ij之间有边 
        if(f[j][1<<(j-1)|s][dep+1]>sum+dis[i]*g[i][j]){
            f[j][1<<(j-1)|s][dep+1]=sum+dis[i]*g[i][j];
            dis[j]=dis[i]+1;
            dfs(1<<(j-1)|s,f[j][1<<(j-1)|s][dep+1],dep+1);
        }
    }
}
int main(){
    scanf("%d%d",&n,&m);lim=(1<<n)-1;
    memset(g,0x3f,sizeof(g));
    for(int i=1,u,v,w;i<=m;i++){
        scanf("%d%d%d",&u,&v,&w);
        g[u][v]=g[v][u]=min(g[u][v],w);
    }
    for(int i=1;i<=n;i++){
        memset(dis,0x3f,sizeof(dis));
        memset(f,0x3f,sizeof(f));
        dis[i]=1;
        dfs(1<<(i-1),0,0);
    }
    printf("%d",ans);
}

原文地址:https://www.cnblogs.com/superminivan/p/11646674.html