bzoj3590: [Snoi2013]Quare

Posted al-ca

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj3590: [Snoi2013]Quare相关的知识,希望对你有一定的参考价值。

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的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ5015[Snoi2017]礼物 矩阵乘法

[LOJ#2255][BZOJ5017][Snoi2017]炸弹

BZOJ5018[Snoi2017]英雄联盟 背包

BZOJ 5018 [Snoi2017]英雄联盟

BZOJ5016[Snoi2017]一个简单的询问 莫队

BZOJ 5017 [Snoi2017]炸弹