1. 程式人生 > >[bzoj3590]Quare——狀壓DP dalaos' blogs Some Links

[bzoj3590]Quare——狀壓DP dalaos' blogs Some Links

題目大意:

給定一個圖,求一個邊的子集,使得整張圖為邊雙連通並且邊的權值和最小。

思路:

資料範圍這麼小,考慮狀壓DP。
題目要求子圖為邊雙連通,邊雙連通可以表示成若干個環套在一起,但是這樣並不方便我們表示狀態。
思考一下,不難發現一個邊雙可以這樣組成:一個邊雙不斷地新增一條鏈並且使這條鏈首尾都和邊雙裡的任意一個點相連。
於是轉移的大致思路便出來了,列舉一條鏈並且將這一條連結入目前的集合中,每一次保證最小代價。
於是我們要預處理任意一條鏈自己本身連通的最小值
還有一個點向一個集合中連邊的最小值
由於一條鏈可能只有一個點,所以還要處理次小值
然後直接轉移就好了。

#include
<bits/stdc++.h>
#define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i) #define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i) #define debug(x) cout<<#x<<"="<<x<<endl #define pii pair<int,int> #define fi first #define se second #define mk make_pair #define
pb push_back
typedef long long ll; using namespace std; void File(){ freopen("bzoj3590.in","r",stdin); freopen("bzoj3590.out","w",stdout); } template<typename T>void read(T &_){ T __=0,mul=1; char ch=getchar(); while(!isdigit(ch)){ if(ch=='-')mul=-1; ch=getchar(); } while(isdigit
(ch))__=(__<<1)+(__<<3)+(ch^'0'),ch=getchar(); _=__*mul; } const int maxn=13; const int maxm=45; const int maxw=(1<<13)+10; const int inf=0x3f3f3f3f; int T,n,m,dp[maxw],all; int G[maxn][maxn],line[maxn][maxn][maxw],mx[maxn][maxw][2]; vector<pii>to[maxn]; void init(){ read(n); read(m); all=(1<<n)-1; REP(i,1,m){ int u,v,w; read(u),read(v),read(w); G[u][v]=min(G[u][v],w); G[v][u]=min(G[v][u],w); to[u].pb(mk(v,w)); to[v].pb(mk(u,w)); } REP(i,1,n)line[i][i][1<<(i-1)]=0; REP(S,1,all){ if(__builtin_popcount(S)==1)continue; REP(L,1,n)if((1<<(L-1))&S) REP(R,1,n)if(((1<<(R-1))&S) && L!=R){ REP(k,1,n)if(((1<<(k-1))&S) && k!=L){ int va=G[L][k],vb=line[k][R][S^(1<<(L-1))]; if(va==inf || vb==inf)continue; line[L][R][S]=min(line[L][R][S],va+vb); } } } REP(i,1,n)REP(S,1,all)if(!((1<<(i-1))&S)){ REP(j,0,to[i].size()-1){ int v=to[i][j].fi,val=to[i][j].se; if(!((1<<(v-1))&S))continue; if(val<mx[i][S][0])swap(mx[i][S][0],mx[i][S][1]),mx[i][S][0]=val; else mx[i][S][1]=min(mx[i][S][1],val); } } } void work(){ dp[1]=0; REP(S,0,all){ if(dp[S]==inf)continue; for(int S0=(all^S);S0;S0=(S0-1)&(all^S)){ int va,vb,vc; REP(i,1,n)if((1<<(i-1))&S0){ if(__builtin_popcount(S0)==1){ va=mx[i][S][0],vb=mx[i][S][1]; if(va!=inf && vb!=inf) dp[S^S0]=min(dp[S^S0],dp[S]+va+vb); break; } REP(j,1,n)if(((1<<(j-1))&S0) && i!=j){ va=mx[i][S][0],vb=mx[j][S][0],vc=line[i][j][S0]; if(va!=inf && vb!=inf && vc!=inf) dp[S^S0]=min(dp[S^S0],dp[S]+va+vb+vc); } } } } if(dp[all]!=inf)printf("%d\n",dp[all]); else puts("impossible"); } int main(){ File(); read(T); while(T--){ memset(line,63,sizeof(line)); memset(mx,63,sizeof(mx)); memset(G,63,sizeof(G)); memset(dp,63,sizeof(dp)); init(); work(); REP(i,0,maxn-1)to[i].clear(); } return 0; }