码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj3590: [Snoi2013]Quare

时间:2019-07-15 09:22:13      阅读:94      评论:0      收藏:0      [点我收藏+]

标签:pos   get   sign   std   fine   数据   max   mes   题意   

bzoj3590: [Snoi2013]Quare

根据题意,图中显然不能有桥,所以可以先用tarjan找桥判“imposibal”。

数据这么小,状压吧,我们可以把这个过程看成这样:我们已经有了一个强连通分量,那么我们要把一个点加入进这个强连通分量,可以找到一条包含这个点的链,且让链的两端都在这个强连通分量里。这么想好像挺可行,那么我们开始设计状态。 首先,f[x]表示x中的点组成强联通分量的最小花费。 g[x][y][S]表示一条链,两端点为x,y,整条链经过S里的点的最小花费。 H[0/1][x][S]表示x点向S中的点的连边的最小值和次小值。 然后就可以愉快的做出来了。

h可以暴力枚举解决:

 1        for(int S=0;S<(1<<n);S++)
 2             for(int i=1;i<=n;i++)
 3             if((S|(1<<(i-1)))!=S)        
 4             {
 5                 for(int j=f(i);j;j=n(j))
 6                 if((S|(1<<(v(j)-1)))==S)
 7                     if(w(j)<h[0][i][S])
 8                     {
 9                         h[1][i][S]=h[0][i][S];
10                         h[0][i][S]=w(j);
11                     }
12                     else if(w(j)<h[1][i][S])h[1][i][S]=w(j);
13             }
14             else h[0][i][S]=h[1][i][S]=0;

g也是一个状压dp,对于x,y,将y分离出来,枚举出边:

 1         memset(g,0x7f,sizeof(g));
 2         for(int S=0;S<(1<<n);S++)
 3         for(int i=1;i<=n;i++)
 4             for(int j=1;j<=n;j++)    
 5                 if( (( S|(1<<(i-1)) )==S) && (( S|(1<<(j-1)) )==S) )
 6                     if(i==j && ( S&~(1<<(i-1)) )==0)g[i][j][S]=0;
 7                     else if(i!=j)    
 8                         for(int k=f(j);k;k=n(k))        
 9                         if( ((1<<(v(k)-1))|S)==S )
10                         g[i][j][S]=min(g[i][j][S],g[i][v(k)][S&~(1<<(j-1))]+w(k));                

这里要注意循环顺序,我开始把S放下边就死了。

然后就是求f了:

 1      memset(f,0x7f,sizeof(f));
 2         for(int i=0;i<n;i++)f[1<<(i)]=0;
 3         for(int S=0;S<(1<<n);S++)
 4         for(int s=0;s<(1<<n);s++)
 5         if((s|S)==S)
 6             for(int x=1;x<=n;x++)
 7             if(((1<<(x-1))|s)!=s && ((1<<(x-1))|S)==S)
 8             for(int y=1;y<=n;y++)
 9             if(((1<<(y-1))|s)!=s && ((1<<(y-1))|S)==S)
10             {
11                 if(x!=y)f[S]=min(f[S],1ll*f[s]+g[x][y][S&~s]+h[0][x][s]+h[0][y][s]);
12                 else    f[S]=min(f[S],1ll*f[s]+g[x][y][S&~s]+h[0][x][s]+h[1][y][s]);
13             }
#include<iostream>
#include<cstring>
#include<bitset>
#include<vector>
#include<cstdio>
#include<queue>
#define MAXN 15
#define MP(a,b) make_pair(a,b)
#define min(a,b) ((a)<(b)?(a):(b))
#define ma(x) memset(x,0,sizeof(x))
using namespace std;
struct edge
{
	int u,v,w,nxt;
	#define u(x)  ed[x].u
	#define v(x)  ed[x].v
	#define w(x)  ed[x].w
	#define n(x)  ed[x].nxt
}ed[100];
int first[MAXN],num_e=1;
#define f(x) first[x]
int T,n,m;

int f[1<<13];
int g[13][13][1<<13];
int h[2][13][1<<13];

int dfn[MAXN],low[MAXN],cnt;
bool bridge[100],pd;
void tarjan(int x,int edg)
{
	dfn[x]=low[x]=++cnt;
	for(int i=f(x);i;i=n(i))
	if(!dfn[v(i)])
	{
		tarjan(v(i),i),low[x]=min(low[x],low[v(i)]);
		if(low[v(i)]>dfn[x])bridge[i]=bridge[i^1]=1;
	}
	else if(i!=(edg^1))low[x]=min(low[x],dfn[v(i)]);
}
void init()
{
	ma(ed);ma(first);ma(f);ma(g);ma(h);ma(dfn);ma(low);ma(bridge);
	pd=cnt=0;num_e=1;
}
inline void add(int u,int v,int w);
signed main()
{
//	freopen("in.txt","r",stdin);

	scanf("%d",&T);
	while(T--)
	{
		init();
		scanf("%d%d",&n,&m);
		int a,b,c;
		for(int i=1;i<=m;i++)
		{
			scanf("%d%d%d",&a,&b,&c);
			add(a,b,c);add(b,a,c);
		}
		for(int i=1;i<=n;i++)
		if(!dfn[i])tarjan(i,0);	
		for(int i=2;i<=num_e;i++)
		if(bridge[i]){puts("impossible");pd=1;break;}
		if(pd)continue;
		memset(h,0x7f,sizeof(h));
		for(int S=0;S<(1<<n);S++)
			for(int i=1;i<=n;i++)
			if((S|(1<<(i-1)))!=S)		
			{
				for(int j=f(i);j;j=n(j))
				if((S|(1<<(v(j)-1)))==S)
					if(w(j)<h[0][i][S])
					{
						h[1][i][S]=h[0][i][S];
						h[0][i][S]=w(j);
					}
					else if(w(j)<h[1][i][S])h[1][i][S]=w(j);
			}
			else h[0][i][S]=h[1][i][S]=0;
		memset(g,0x7f,sizeof(g));
		for(int S=0;S<(1<<n);S++)
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)	
				if( (( S|(1<<(i-1)) )==S) && (( S|(1<<(j-1)) )==S) )
					if(i==j && ( S&~(1<<(i-1)) )==0)g[i][j][S]=0;
					else if(i!=j)	
						for(int k=f(j);k;k=n(k))		
						if( ((1<<(v(k)-1))|S)==S )
						g[i][j][S]=min(g[i][j][S],g[i][v(k)][S&~(1<<(j-1))]+w(k));
		memset(f,0x7f,sizeof(f));
		for(int i=0;i<n;i++)f[1<<(i)]=0;
		for(int S=0;S<(1<<n);S++)
		for(int s=0;s<(1<<n);s++)
		if((s|S)==S)
			for(int x=1;x<=n;x++)
			if(((1<<(x-1))|s)!=s && ((1<<(x-1))|S)==S)
			for(int y=1;y<=n;y++)
			if(((1<<(y-1))|s)!=s && ((1<<(y-1))|S)==S)
			{
				if(x!=y)f[S]=min(f[S],1ll*f[s]+g[x][y][S&~s]+h[0][x][s]+h[0][y][s]);
				else    f[S]=min(f[S],1ll*f[s]+g[x][y][S&~s]+h[0][x][s]+h[1][y][s]);
			}
		printf("%d\n",f[(1<<n)-1]);
	}
}
inline void add(int u,int v,int w)
{
	++num_e;
	u(num_e)=u;
	v(num_e)=v;
	w(num_e)=w;
	n(num_e)=f(u);
	f(u)=num_e;
}

 

bzoj3590: [Snoi2013]Quare

标签:pos   get   sign   std   fine   数据   max   mes   题意   

原文地址:https://www.cnblogs.com/Al-Ca/p/11186749.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!