【BZOJ3590】[Snoi2013]Quare 状压DP

【BZOJ3590】[Snoi2013]Quare

Description

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

Input

    输入文件有多组数据,第1行为 1 个整数t,为 case总数,接下来按顺序给出每个case 描述,首先是两个整数 n,m(1≤n≤12, 1≤m≤40)分别表示城市数量和公路数量,下面m行每行 3个整数x,y,c 描述了一条公路的情况:x城市与y城市之间的一条公路,抢修该公路需要 c个单位时间。
注意上面所说的两城市间可能有多条公路。

Output

    按顺序输出每个 case 的结果,如果找不到一条合适的方案,则输出一行“impossible”,否则输出一个整数,为抢修的最优方案所需要的总时间。

Sample Input

2
4 6
1 2 1
1 3 2
1 3 3
2 4 2
3 4 1
2 3 1
2 1
1 2 3

Sample Output

6
impossible

题解:容易发现最优解一定是由若干个环套在一起,也就是说由一个强连通分量加上一个链组成一个更大的强联通分量。所以我们设如下状态:

h1[x][S],h2[x][S]分别代表点x到集合S的所有边的边权最小值和次小值。
g[x][y][S]代表一条链,包含S中的点,且两端点分别为x和y的最小花费。
f[x]表示S中的点组成强连通分量的最小花费。

转移时相当于枚举子集。不过注意当更新f[x]时,如果自己中只有一个点则只能用h1和h2转移。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=(1<<12)+4;
int n,m,msk,cas,cnt;

int head[13],next[90],val[90],to[90],Log[maxn],h1[13][maxn],h2[13][maxn],g[13][13][maxn],f[maxn];

inline void add(int a,int b,int c)
{
	to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++;
}
inline void work()
{
	scanf("%d%d",&n,&m),msk=(1<<n)-1;
	int i,S,T,ta,tb,a,b,c;
	memset(head,-1,sizeof(head)),cnt=0;
	for(i=0;i<m;i++)	scanf("%d%d%d",&a,&b,&c),a--,b--,add(a,b,c),add(b,a,c);
	for(i=0;i<n;i++)	Log[1<<i]=i;
	memset(h1,0x0f,sizeof(h1)),memset(h2,0x0f,sizeof(h2)),memset(g,0x0f,sizeof(g)),memset(f,0x0f,sizeof(f));
	for(S=0;S<=msk;S++)
	{
		for(ta=(msk^S);ta;ta-=ta&-ta)
		{
			a=Log[ta&-ta];
			for(i=head[a];i!=-1;i=next[i])	if((S>>to[i])&1)
			{
				if(val[i]<h1[a][S])	h2[a][S]=h1[a][S],h1[a][S]=val[i];
				else	h2[a][S]=min(h2[a][S],val[i]);
			}
		}
	}
	for(i=0;i<n;i++)	g[i][i][1<<i]=f[1<<i]=0;
	for(S=1;S<=msk;S++)
	{
		for(ta=S;ta;ta-=ta&-ta)	for(tb=S;tb;tb-=tb&-tb)
		{
			a=Log[ta&-ta],b=Log[tb&-tb];
			if(a==b)	continue;
			for(i=head[b];i!=-1;i=next[i])	if((S>>to[i])&1)
			{
				g[a][b][S]=min(g[a][b][S],g[a][to[i]][S^(1<<b)]+val[i]);
			}
		}
	}
	for(S=1;S<=msk;S++)
	{
		if(S==(S&-S))	continue;
		for(T=(S-1)&S;T;T=(T-1)&S)
		{
			/*if(T==(T&-T))
			{
				a=Log[T],f[S]=min(f[S],f[S^T]+h1[a][S^T]+h2[a][S^T]);
				for(i=head[a];i!=-1;i=next[i]) if(((S^T)>>to[i])&1)
					for(j=head[a];j!=-1;j=next[j]) if((((S^T)>>to[j])&1)&&i!=j)
						f[S]=min(f[S],g[to[i]][to[j]][S^T]+val[i]+val[j]);
				continue;
			}
			if((S^T)==((S^T)&-(S^T)))
			{
				a=Log[S^T],f[S]=min(f[S],f[T]+h1[a][T]+h2[a][T]);
				for(i=head[a];i!=-1;i=next[i]) if((T>>to[i])&1)
					for(j=head[a];j!=-1;j=next[j]) if(((T>>to[j])&1)&&i!=j)
						f[S]=min(f[S],g[to[i]][to[j]][T]+val[i]+val[j]);
				continue;
			}*/
			for(ta=T;ta;ta-=ta&-ta)	for(tb=T;tb;tb-=tb&-tb)
			{
				a=Log[ta&-ta],b=Log[tb&-tb];
				if(a==b)	f[S]=min(f[S],f[S^T]+g[a][b][T]+h1[a][S^T]+h2[a][S^T]);
				else	f[S]=min(f[S],f[S^T]+g[a][b][T]+h1[a][S^T]+h1[b][S^T]);
			}
		}
	}
	if(f[msk]==0x0f0f0f0f)	puts("impossible");
	else	printf("%d\n",f[msk]);
}
int main()
{
	scanf("%d",&cas);
	while(cas--)	work();
	return 0;
}//2 4 6 1 2 1 1 3 2 1 3 3 2 4 2 3 4 1 2 3 1 2 1 1 2 3
posted @ 2018-03-18 15:07  CQzhangyu  阅读(769)  评论(0编辑  收藏  举报