bzoj3590: [Snoi2013]Quare
根据题意,图中显然不能有桥,所以可以先用tarjan找桥判“imposibal”。
数据这么小,状压吧,我们可以把这个过程看成这样:我们已经有了一个强连通分量,那么我们要把一个点加入进这个强连通分量,可以找到一条包含这个点的链,且让链的两端都在这个强连通分量里。这么想好像挺可行,那么我们开始设计状态。 首先,f[x]表示x中的点组成强联通分量的最小花费。 g[x][y][S]表示一条链,两端点为x,y,整条链经过S里的点的最小花费。 H[0/1][x][S]表示x点向S中的点的连边的最小值和次小值。 然后就可以愉快的做出来了。
h可以暴力枚举解决:
1 for(int S=0;S<(1<<n);S++) 2 for(int i=1;i<=n;i++) 3 if((S|(1<<(i-1)))!=S) 4 { 5 for(int j=f(i);j;j=n(j)) 6 if((S|(1<<(v(j)-1)))==S) 7 if(w(j)<h[0][i][S]) 8 { 9 h[1][i][S]=h[0][i][S]; 10 h[0][i][S]=w(j); 11 } 12 else if(w(j)<h[1][i][S])h[1][i][S]=w(j); 13 } 14 else h[0][i][S]=h[1][i][S]=0;
g也是一个状压dp,对于x,y,将y分离出来,枚举出边:
1 memset(g,0x7f,sizeof(g)); 2 for(int S=0;S<(1<<n);S++) 3 for(int i=1;i<=n;i++) 4 for(int j=1;j<=n;j++) 5 if( (( S|(1<<(i-1)) )==S) && (( S|(1<<(j-1)) )==S) ) 6 if(i==j && ( S&~(1<<(i-1)) )==0)g[i][j][S]=0; 7 else if(i!=j) 8 for(int k=f(j);k;k=n(k)) 9 if( ((1<<(v(k)-1))|S)==S ) 10 g[i][j][S]=min(g[i][j][S],g[i][v(k)][S&~(1<<(j-1))]+w(k));
这里要注意循环顺序,我开始把S放下边就死了。
然后就是求f了:
1 memset(f,0x7f,sizeof(f)); 2 for(int i=0;i<n;i++)f[1<<(i)]=0; 3 for(int S=0;S<(1<<n);S++) 4 for(int s=0;s<(1<<n);s++) 5 if((s|S)==S) 6 for(int x=1;x<=n;x++) 7 if(((1<<(x-1))|s)!=s && ((1<<(x-1))|S)==S) 8 for(int y=1;y<=n;y++) 9 if(((1<<(y-1))|s)!=s && ((1<<(y-1))|S)==S) 10 { 11 if(x!=y)f[S]=min(f[S],1ll*f[s]+g[x][y][S&~s]+h[0][x][s]+h[0][y][s]); 12 else f[S]=min(f[S],1ll*f[s]+g[x][y][S&~s]+h[0][x][s]+h[1][y][s]); 13 }
#include<iostream> #include<cstring> #include<bitset> #include<vector> #include<cstdio> #include<queue> #define MAXN 15 #define MP(a,b) make_pair(a,b) #define min(a,b) ((a)<(b)?(a):(b)) #define ma(x) memset(x,0,sizeof(x)) using namespace std; struct edge { int u,v,w,nxt; #define u(x) ed[x].u #define v(x) ed[x].v #define w(x) ed[x].w #define n(x) ed[x].nxt }ed[100]; int first[MAXN],num_e=1; #define f(x) first[x] int T,n,m; int f[1<<13]; int g[13][13][1<<13]; int h[2][13][1<<13]; int dfn[MAXN],low[MAXN],cnt; bool bridge[100],pd; void tarjan(int x,int edg) { dfn[x]=low[x]=++cnt; for(int i=f(x);i;i=n(i)) if(!dfn[v(i)]) { tarjan(v(i),i),low[x]=min(low[x],low[v(i)]); if(low[v(i)]>dfn[x])bridge[i]=bridge[i^1]=1; } else if(i!=(edg^1))low[x]=min(low[x],dfn[v(i)]); } void init() { ma(ed);ma(first);ma(f);ma(g);ma(h);ma(dfn);ma(low);ma(bridge); pd=cnt=0;num_e=1; } inline void add(int u,int v,int w); signed main() { // freopen("in.txt","r",stdin); scanf("%d",&T); while(T--) { init(); scanf("%d%d",&n,&m); int a,b,c; for(int i=1;i<=m;i++) { scanf("%d%d%d",&a,&b,&c); add(a,b,c);add(b,a,c); } for(int i=1;i<=n;i++) if(!dfn[i])tarjan(i,0); for(int i=2;i<=num_e;i++) if(bridge[i]){puts("impossible");pd=1;break;} if(pd)continue; memset(h,0x7f,sizeof(h)); for(int S=0;S<(1<<n);S++) for(int i=1;i<=n;i++) if((S|(1<<(i-1)))!=S) { for(int j=f(i);j;j=n(j)) if((S|(1<<(v(j)-1)))==S) if(w(j)<h[0][i][S]) { h[1][i][S]=h[0][i][S]; h[0][i][S]=w(j); } else if(w(j)<h[1][i][S])h[1][i][S]=w(j); } else h[0][i][S]=h[1][i][S]=0; memset(g,0x7f,sizeof(g)); for(int S=0;S<(1<<n);S++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if( (( S|(1<<(i-1)) )==S) && (( S|(1<<(j-1)) )==S) ) if(i==j && ( S&~(1<<(i-1)) )==0)g[i][j][S]=0; else if(i!=j) for(int k=f(j);k;k=n(k)) if( ((1<<(v(k)-1))|S)==S ) g[i][j][S]=min(g[i][j][S],g[i][v(k)][S&~(1<<(j-1))]+w(k)); memset(f,0x7f,sizeof(f)); for(int i=0;i<n;i++)f[1<<(i)]=0; for(int S=0;S<(1<<n);S++) for(int s=0;s<(1<<n);s++) if((s|S)==S) for(int x=1;x<=n;x++) if(((1<<(x-1))|s)!=s && ((1<<(x-1))|S)==S) for(int y=1;y<=n;y++) if(((1<<(y-1))|s)!=s && ((1<<(y-1))|S)==S) { if(x!=y)f[S]=min(f[S],1ll*f[s]+g[x][y][S&~s]+h[0][x][s]+h[0][y][s]); else f[S]=min(f[S],1ll*f[s]+g[x][y][S&~s]+h[0][x][s]+h[1][y][s]); } printf("%d\n",f[(1<<n)-1]); } } inline void add(int u,int v,int w) { ++num_e; u(num_e)=u; v(num_e)=v; w(num_e)=w; n(num_e)=f(u); f(u)=num_e; }
波澜前,面不惊。