题目
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;
}