LUGOU 3959 宝藏 (noip 2017 day2 T2)

传送门

解题思路

去年noip现在拿来写。。思路还是听清楚的,记忆化搜索,f[S]表示现在选了集合S时的最小代价,dis[i]表示达到最优时i这个点的深度。f[S| (1< < i-1) ]=f[S]+a[i][j]*(dis[i]+1)

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>

using namespace std;
const int MAXN = 15;
const int inf = 0x3f3f3f3f;
typedef long long LL; 

inline int rd(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch))  {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
}

int n,m,a[MAXN][MAXN],dis[MAXN];
LL ans=1e9;
LL f[1<<MAXN];

inline void dfs(int S){
    for(register int i=1;i<=n;i++)if((1<<i-1)&S){
        for(register int j=1;j<=n;j++)if(!((1<<j-1)&S) && a[i][j]!=inf)
            if(f[S|(1<<j-1)]>f[S]+(dis[i]+1)*a[i][j]){
                int t=dis[j];
                dis[j]=dis[i]+1;
                f[S|(1<<j-1)]=min(f[S|(1<<j-1)],f[S]+dis[j]*a[i][j]);
                dfs(S|(1<<j-1));
                dis[j]=t;
            }
    }
}

int main(){
    memset(a,0x3f,sizeof(a));
    n=rd();m=rd();
    for(register int i=1;i<=m;i++){
        int x=rd(),y=rd(),z=rd();
        a[x][y]=a[y][x]=min(a[x][y],z);
    }
    for(register int i=1;i<=n;i++){
        memset(dis,0,sizeof(dis));
        memset(f,0x3f,sizeof(f));
        f[(1<<i-1)]=0;
        dfs(1<<(i-1));ans=min(ans,f[(1<<n)-1]);
    }
    printf("%lld",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/sdfzsyq/p/9676924.html