bzoj 3590: [Snoi2013]Quare

来源:互联网 发布:matlab 矩阵动态添加 编辑:程序博客网 时间:2024/04/27 22:08

题意:

在一个图中选出一个权值和最小边,使这个子图是一个包含所有点的边双连通图。

题解:

好题。
反正没有想到是状压dp。
于是orz题解:Lethelody
主要使用到了边双连通图的一个性质:一个边双一定是由一个边双+一条链组成。(因为一个点也是边双,所以对于一个环的情况也成立)
具体转移上面那篇已经讲得很详尽了,这里就不再累述。
code:

#include<cstdio>#include<cstdlib>#include<cstring>#include<iostream>using namespace std;struct node{    int y,c,next;}a[90];int len,last[13];int f[4200],h[4200][13][2],g[4200][13][13];int n,m;void ins(int x,int y,int c){    a[++len].y=y;a[len].c=c;    a[len].next=last[x];last[x]=len;}void update(int s,int x,int c){    if(c<h[s][x][0]) swap(h[s][x][0],c);    if(c<h[s][x][1]) swap(h[s][x][1],c);}void init(){    memset(f,63,sizeof(f));    memset(h,63,sizeof(h));    memset(g,63,sizeof(g));}void pre(){    for(int s=1;s<(1<<n);s++)        for(int x=1;x<=n;x++)            for(int i=last[x];i;i=a[i].next)            {                int y=a[i].y;                if(s&(1<<(y-1))) update(s,x,a[i].c);            }}void cmin(int &x,int y) {x=x<y?x:y;}int main(){    int T;scanf("%d",&T);    while(T--)    {        scanf("%d %d",&n,&m);        len=0;memset(last,0,sizeof(last));        for(int i=1;i<=m;i++)        {            int x,y,c;scanf("%d %d %d",&x,&y,&c);            ins(x,y,c);ins(y,x,c);        }        init();pre();        for(int i=1;i<=n;i++) g[(1<<(i-1))][i][i]=0;        for(int s=1;s<(1<<n);s++)        for(int x1=1;x1<=n;x1++)        for(int x2=1;x2<=n;x2++)            if(g[s][x1][x2]<99999999)            {                for(int i=last[x1];i;i=a[i].next)                {                    int y=a[i].y;                    if((s&(1<<(y-1)))==0) cmin(g[s|(1<<(y-1))][y][x2],g[s][x1][x2]+a[i].c);                }                for(int i=last[x2];i;i=a[i].next)                {                    int y=a[i].y;                    if((s&(1<<(y-1)))==0) cmin(g[s|(1<<(y-1))][x1][y],g[s][x1][x2]+a[i].c);                }            }        for(int i=0;i<n;i++) f[1<<i]=0;        for(int s=1;s<(1<<n);s++)            if(f[s]<99999999)            {                int x=((1<<n)-1)^s;                for(int t=x;t;t=x&(t-1))                {                    for(int x1=1;x1<=n;x1++)                    for(int x2=1;x2<=n;x2++)                        if(g[t][x1][x2]<99999999)                        {                            if(x1==x2) cmin(f[s|t],f[s]+g[t][x1][x1]+h[s][x1][0]+h[s][x1][1]);                            else cmin(f[s|t],f[s]+g[t][x1][x2]+h[s][x1][0]+h[s][x2][0]);                        }                }            }        if(f[(1<<n)-1]<99999999) printf("%d\n",f[(1<<n)-1]);        else printf("impossible\n");    }}