1. 程式人生 > >【BZOJ3590】[Snoi2013]Quare 狀壓DP

【BZOJ3590】[Snoi2013]Quare 狀壓DP

估計 進行 puts 委員會 style scrip 枚舉 ring continue

【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

【BZOJ3590】[Snoi2013]Quare 狀壓DP