NOIP 模擬 $33\; \rm Connect$
阿新 • • 發佈:2021-08-08
題解
題解
狀壓 \(\rm DP\)。
從 \(1\) 到 \(n\) 一共只要一條路徑,那麼就是一條鏈,只要維護一個點集和當前鏈的末尾就行。
設 \(\rm dp_{i,j}\) 為 \(i\) 的點集末尾為 \(j\) 的最大權。
轉移有兩種:
-
在鏈的末尾加上一個點。
-
在鏈的末尾加上一個點集,這個點集就代表無關的聯通塊只能和答案鏈最多連線一個點。
Code
#include<bits/stdc++.h> #define ri register signed #define p(i) ++i namespace IO{ char buf[1<<21],*p1=buf,*p2=buf; #define gc() p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?(-1):*p1++ struct nanfeng_stream{ template<typename T>inline nanfeng_stream operator>>(T &x) { ri f=0;x=0;register char ch=gc(); while(!isdigit(ch)) f|=ch=='-',x=gc(); while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=gc(); return x=f?-x:x,*this; } }cin; } using IO::cin; namespace nanfeng{ #define FI FILE *IN #define FO FILE *OUT template<typename T>inline T cmax(T x,T y) {return x>y?x:y;} template<typename T>inline T cmin(T x,T y) {return x>y?y:x;} static const int N=15,INF=-1044266559; int dis[N][N],sum[1<<N],dp[1<<N][N],S,n,m; inline int main() { //FI=freopen("nanfeng.in","r",stdin); //FO=freopen("nanfeng.out","w",stdout); cin >> n >> m; for (ri i(1),u,v,w;i<=m;p(i)) { cin >> u >> v >> w; u-=1,v-=1; dis[u][v]=dis[v][u]=w; } S=1<<n; for (ri i(1);i<S;p(i)) for (ri j(0);j<n;p(j)) for (ri k(j+1);k<n;p(k)) if (((i>>j)&1)&&((i>>k)&1)) sum[i]+=dis[j][k]; memset(dp,-0x3f,sizeof(dp)); dp[1][0]=0; for (ri i(1);i<S;p(i)) { for (ri j(0);j<n;p(j)) { if (dp[i][j]==INF) continue; for (ri k(0);k<n;p(k)) if (dis[j][k]&&!((i>>k)&1)) dp[i|1<<k][k]=cmax(dp[i|1<<k][k],dp[i][j]+dis[j][k]); ri s=(i^((1<<n)-1)); for (ri k(s);k;k=(k-1)&s) dp[i|k][j]=cmax(dp[i|k][j],dp[i][j]+sum[k|(1<<j)]); } } printf("%d\n",sum[(1<<n)-1]-dp[(1<<n)-1][n-1]); return 0; } } int main() {return nanfeng::main();}