1. 程式人生 > >【狀壓DP】BZOJ4479吃貨jyy

【狀壓DP】BZOJ4479吃貨jyy

分析:

把問題轉化一下,所謂的迴路只需要滿足:每個點得度數均為偶數即可。
然後可以先把必走的邊忽略,讓這些邊聯通且滿足上述條件。
3 n 3^n 的DP,表示每一個點:不連通/度數為奇/度數為偶。(這裡要特別注意必走邊,儘管我們忽略了它們,但是它們是實際存在的,要參與連通性計算,只不過代價為0,因為它們的代價我們會最後加上)

然後再搞一個 2 n 2^n 的DP,表示連結某些點的最小代價。

然後對每個 3 n

3^n 的狀態,找到哪些點應該補度數。求出一個對應的 2 n 2^n 的狀態。兩個狀態之和加上最開始忽略的必走邊就是答案。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath> #include<queue> #define SF scanf #define PF printf #define MAXS 1594423 #define MAXN 14 #define INF 0x3f3f3f3f #define MAXB 8292 using namespace std; int n,m,w1; int W; struct node{ int x; node *nxt; }edge[MAXN*10]; node *head[MAXN],*ncnt=edge; int b[MAXN],p[MAXN]; int dp[MAXS],f[MAXB]; void add_edge(int x,int y){ ncnt++; ncnt->x=y; ncnt->nxt=head[x]; head[x]=ncnt; } int c(int s,int pos){ return (s/p[pos])%3; } int tr(int s,int pos){ if(c(s,pos)==1) return s+p[pos]; else return s-p[pos]; } int dist[MAXN][MAXN]; void prepare(){ for(int k=0;k<n;k++) for(int i=0;i<n;i++) for(int j=0;j<n;j++) dist[i][j]=min(dist[i][j],dist[i][k]+dist[k][j]); b[0]=1; p[0]=1; for(int i=1;i<=n;i++){ b[i]=b[i-1]*2; p[i]=p[i-1]*3; } memset(f,0x3f,sizeof f); f[0]=0; for(int mask=0;mask<b[n];mask++){ if(mask==INF) continue; for(int i=0;i<n;i++){ if(mask&b[i]) continue; for(int j=0;j<n;j++){ if((mask&b[j])||j==i) continue; f[mask|b[i]|b[j]]=min(f[mask|b[i]|b[j]],f[mask]+dist[i][j]); } } } } void Update(int &x,int y){ x=min(x,y); } int used[MAXN]; queue<int> q; void solve(){ memset(dp,INF,sizeof dp); dp[2]=0; q.push(2); while(!q.empty()){ int mask=q.front(); q.pop(); int tmp=0; for(int i=0;i<n;i++) if(c(mask,i)!=0) used[tmp++]=i; for(int i=0;i<n;i++) if(c(mask,i)==0){ int mask1=mask+2*p[i]; for(node *v=head[i];v!=NULL;v=v->nxt) if(c(mask1,v->x)!=0){ if(dp[mask1]==INF) q.push(mask1); Update(dp[mask1],dp[mask]); } for(int j=0;j<tmp;j++){ if(dist[i][used[j]]==INF) continue; mask1=tr(mask,used[j])+p[i]; if(dp[mask1]==INF) q.push(mask1); Update(dp[mask1],dp[mask]+dist[i][used[j]]); } } } } bool check(int mask){ for(int i=0;i<n;i++) if(head[i]!=NULL&&c(mask,i)==0) return 0; return 1; } int d[MAXN]; int get_ans(){ int res=INF; for(int mask=2;mask<p[n];mask++){ if(check(mask)==0) continue; int t=0; for(int i=0;i<n;i++){ if((d[i]^((mask/p[i])%3==1))==1){ t|=b[i]; } } //PF("{%d %d %d %d %d %d %d}\n",mask,t,((mask/p[0])%3==1)^d[0],d[1],d[2],d[3],d[4]); Update(res,dp[mask]+f[t]); } return res; } int main(){ SF("%d%d",&n,&m); memset(dist,INF,sizeof dist); int u,v; for(int i=1;i<=m;i++){ SF("%d%d%d",&u,&v,&w1); u--; v--; W+=w1; Update(dist[u][v],w1); dist[v][u]=dist[u][v]; add_edge(u,v); add_edge(v,u); d[u]^=1; d[v]^=1; } SF("%d",&m); for(int i=1;i<=m;i++){ SF("%d%d%d",&u,&v,&w1); u--; v--; Update(dist[u][v],w1); dist[v][u]=dist[u][v]; } for(int i=0;i<n;i++) dist[i][i]=0; prepare(); solve(); PF("%d",get_ans()+W); }