BZOJ 3590 [Snoi2013]Quare [状压DP]

题目

4.20四川芦山地震发生后,抗震救灾委员会接到一个紧急任务,四川省给
该委员会发了一份地图,这份地图给出了该省一些城市的情况:任两个城市是
用一条或多条公路连接起来的,也可以没有公路连接,但是每个城市都可以直
接或间接地到达另外的城市,注意这些公路是可以双向行驶的。由于最近余震、
暴雨造成泥石流倾泻,使得车辆在这些公路上行驶很不安全,于是四川省决定
尽快对部分公路进行抢修,以保障救援车辆行车安全。
该省对所有的公路情况都进行了勘察,分析估计了抢修某段公路所需要花
费的时间,并记录在地图中。现在该省希望抗震救灾委员会能找到一个方案,
该方案决定出哪些公路需要抢修,使得抢修后的公路仍能保证任意两个城市之
间都能直接或间接地相连,同时为了安全起见,即使某一条抢修的公路被泥石
流阻断了,任意两城市仍能保持这个性质。由于时间紧迫,抗震救灾委员会还
需保证找到的这个方案总抢修时间最短。
n,m(1≤n≤12, 1≤m≤40)

题解

n这么小,考虑状压。
大边双=小边双+一条链
用 $g[S][i][j]$ 表示S中的点组成一条链,其中$i$、$j$为链的两端的最少消耗
用 $h1[i][S],h2[i][S]$ 分别表示从i这个点到S这个点集的最短距离和次短距离
用 $f[S]$ 表示S这个点集中的点组成边双的最小耗费,也就是答案。
$g[S][i][j]=g[S^(1<<v)][i][v]+val[v->j]$
··························································································
$f[S]=g[s1][a][b]+h1[a][s2]+h2[a][s2](a=b)$
··························································································
$f[S]=g[s1][a][b]+h1[a][s2]+h1[b][s2](a≠b)$

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=44;
const int maxm=(1<<12)+1;
struct point
{
    int to;
    int nxt;
    int w;
}edge[maxn*2];
int T,n,m,tot;
int head[maxn];
int g[maxm][14][14],h1[14][maxm],h2[14][maxm];
int f[maxm],Log[maxm];

inline void add(int u,int v,int w)
{
    tot++;
    edge[tot].nxt=head[u];
    edge[tot].to=v;
    edge[tot].w=w;
    head[u]=tot;
}

inline int lowbit(int x)
{
    return x&-x;
}

inline void solve()
{
    int i,S,T,ta,tb,a,b,c;
    for(int i=0;i<n;i++) Log[1<<i]=i;
    int up=(1<<n)-1;
    for(int i=0;i<n;i++)
    {
        g[1<<i][i][i]=0;
        f[1<<i]=0;
    }
    for(int S=1;S<=up;S++)
        for(int i=up^S;i;i-=lowbit(i))
        {
            int a=Log[lowbit(i)];
            for(int j=head[a];j;j=edge[j].nxt)
            {
                int v=edge[j].to;
                if((1<<v)&S)
                {
                    if(h1[a][S]>edge[j].w)
                    {
                        h2[a][S]=h1[a][S];
                        h1[a][S]=edge[j].w;
                    }
                    else
                        h2[a][S]=min(h2[a][S],edge[j].w);
                }
            }
        }
    for(int S=1;S<=up;S++)
    {
        for(int p1=S;p1;p1-=lowbit(p1))
        for(int p2=S;p2;p2-=lowbit(p2))
        {
            int a=Log[lowbit(p1)],b=Log[lowbit(p2)];
            if(a==b) continue;
            for(int i=head[a];i;i=edge[i].nxt)
            {
                int v=edge[i].to;
                if((1<<v)&S)
                g[S][a][b]=min(g[S][a][b],g[S^(1<<a)][v][b]+edge[i].w);
            }
        }
    }
    for(int S=1;S<=up;S++)
    {
        if(S==lowbit(S)) continue;
        for(int T=(S-1)&S;T;T=S&(T-1))
        {
            for(int p1=T;p1;p1-=lowbit(p1))
            for(int p2=T;p2;p2-=lowbit(p2))
            {
                int a=Log[lowbit(p1)],b=Log[lowbit(p2)];
                if(a==b)
                    f[S]=min(f[S],f[S^T]+g[T][a][b]+h1[a][S^T]+h2[a][S^T]);
                else f[S]=min(f[S],f[S^T]+g[T][a][b]+h1[a][S^T]+h1[b][S^T]);
            }
        }
    }
    if(f[up]==0x0f0f0f0f) puts("impossible");
    else printf("%d\n",f[up]);
}

inline void init()
{
    tot=0;
    memset(head,0,sizeof(head));
    memset(f,0x0f,sizeof(f));
    memset(g,0x0f,sizeof(g));
    memset(h1,0x0f,sizeof(h1));
    memset(h2,0x0f,sizeof(h2));
}

int main()
{
    scanf("%d",&T);
    while(T--)
    {
        init();
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            u--,v--;
            add(u,v,w),add(v,u,w);
        }
        solve();
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/linda-fcj/p/9049686.html
今日推荐