洛谷3959 寶藏(狀壓DP)
阿新 • • 發佈:2018-11-10
題面
Solution
顯然我們看到\(n\)這麼小,可以狀壓一下對吧。
然後考慮一個\(DP\):
設\(dp[s]\)表示選的數為s這個集合的答案,那麼可以這麼轉移:
\(dp[s|(1<<v-1)]=max(dp[s|1<<v-1)],dp[s]+w[i]*dep[u]\)
然後就直接dfs算一下深度然後亂搞?
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<math.h> #include<algorithm> #include<iostream> #include<queue> #define ll long long #define file(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout) using namespace std; inline int gi(){ int sum=0,f=1;char ch=getchar(); while(ch>'9' || ch<'0'){if(ch=='-')f=-f;ch=getchar();} while(ch>='0' && ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();} return f*sum; } inline ll gl(){ ll sum=0,f=1;char ch=getchar(); while(ch>'9' || ch<'0'){if(ch=='-')f=-f;ch=getchar();} while(ch>='0' && ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();} return f*sum; } const int maxn=20; ll dp[200010]; int n,dep[maxn],g[maxn][maxn]; void Dp(int s){//挖通的集合 for(int u=1;u<=n;u++) if(s&(1<<u-1)) for(int v=1;v<=n;v++){ if(!(s&(1<<v-1)) && g[u][v]!=g[0][0] && dp[s]+g[u][v]*dep[u]<dp[s|(1<<v-1)]){ dp[s|(1<<v-1)]=dp[s]+g[u][v]*dep[u];int tmp=dep[v];dep[v]=dep[u]+1; Dp(s|(1<<v-1)); dep[v]=tmp; } } } int main(){ int i,j,m,k; n=gi();m=gi();memset(g,127,sizeof(g)); for(i=1;i<=m;i++){ int u=gi(),v=gi(),W=gi(); if(W<g[u][v])g[u][v]=g[v][u]=W; } ll ans=1000000000; for(i=1;i<=n;i++){ memset(dp,127,sizeof(dp));memset(dep,0,sizeof(dep)); dp[1<<(i-1)]=0;dep[i]=1; Dp(1<<i-1); ans=min(ans,dp[(1<<n)-1]); } printf("%lld\n",ans); return 0; }