bzoj3590: [Snoi2013]Quare

传送门

impossible打错结果WA了半个小时我觉得自己也是挺强的……
顺便发现我模拟赛的时候从来没有打对过任何一道dp……
果然dp就是智商的分水岭啊QAQ
首先最优解肯定是若干个环套在一起,或者说一个强连通分量加上一条链可以组成一个更大的强联通分量。
我们分别记录一下状态,\(h1[u][S]\)表示点\(u\)\(S\)的点集中的随便哪个点的最小距离,\(h2[u][S]\)表示次小距离
\(g[u][v][S]\)表示一条链,其中链的两端为\(u,v\),链上的点为\(S\)的最小花费
\(f[S]\)表示\(S\)中的点组成强联通分量时的最小花费
然后用强联通分量组成更大的强联通分量即可
代码抄袭CQzhangyu的

//minamoto
#include<bits/stdc++.h>
#define rint register int
#define fp(i,a,b) for(register int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(register int i=a,I=b-1;i>I;--i)
#define go(u) for(register int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
using namespace std;
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
const int N=105,M=(1<<12)+5;
int n,m,lim,T,u,v,vva,w,tot;
struct eg{int v,nx,w;}e[N];int head[N],val[N],Log[M],h1[15][M],h2[15][M],g[15][15][M],f[M];
inline void add(int u,int v,int w){e[++tot]={v,head[u],w},head[u]=tot;}
void solve(){
    scanf("%d%d",&n,&m),lim=(1<<n)-1;
    memset(head,0,sizeof(head)),tot=0;
    fp(i,0,m-1)scanf("%d%d%d",&u,&v,&w),add(u-1,v-1,w),add(v-1,u-1,w);
    fp(i,0,n-1)Log[1<<i]=i;
    memset(h1,0x0f,sizeof(h1)),memset(h2,0x0f,sizeof(h2)),memset(g,0x0f,sizeof(g)),memset(f,0x0f,sizeof(f));
    fp(S,0,lim)for(rint ta=lim^S;ta;ta-=ta&-ta){
        u=Log[ta&-ta];go(u)if(S&(1<<v)){
            if(e[i].w<h1[u][S])h2[u][S]=h1[u][S],h1[u][S]=e[i].w;
            else cmin(h2[u][S],e[i].w);
        }
    }
    fp(i,0,n-1)g[i][i][1<<i]=f[1<<i]=0;
    fp(S,1,lim)for(rint ta=S;ta;ta-=ta&-ta)for(rint tb=S;tb;tb-=tb&-tb){
        u=Log[ta&-ta],vva=Log[tb&-tb];if(u==vva)continue;
        go(vva)if(S&(1<<v))cmin(g[u][vva][S],g[u][v][S^(1<<vva)]+e[i].w);
    }
    fp(S,1,lim){
        if(S==(S&-S))continue;
        for(rint T=(S-1)&S;T;T=(T-1)&S)for(rint ta=T;ta;ta-=ta&-ta)for(rint tb=T;tb;tb-=tb&-tb){
            u=Log[ta&-ta],vva=Log[tb&-tb];
            if(u==vva)cmin(f[S],f[S^T]+g[u][vva][T]+h1[u][S^T]+h2[u][S^T]);
            else cmin(f[S],f[S^T]+g[u][vva][T]+h1[u][S^T]+h1[vva][S^T]);
        }
    }
    if(f[lim]==0x0f0f0f0f)puts("impossible");
    else printf("%d\n",f[lim]);
}
int main(){
//  freopen("testdata.in","r",stdin);
    scanf("%d",&T);
    while(T--)solve();
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/bztMinamoto/p/10017800.html