loj 6043「雅礼集训 2017 Day7」蛐蛐国的修墙方案

loj

爆搜?

爆搜!

先分析一下,因为我们给出的是一个排列,然后让\(i\)\(p_i\)连边,那么我们一定会得到若干个环,最后要使得所有点度数为1,也就是这些环有完备匹配,那么最后一定全是偶环.对于一个环,我们选点一定是隔一个选一个,所以每个环只有\(2\)种选法.如果我们先考虑长度为\(2\)的环,这种环选编号小的点显然更优,因为他要的是括号序列,左括号在越前面越好;剩下的环一定长度\(\ge 4\),那么这种环个数不超过\(\frac{100}{4}=25\)个,枚举每种环的选择情况即可,复杂度\(2^{25}\).注意可以从前往后考虑,这样方便剪枝,出现右括号无法匹配就return

#include<bits/stdc++.h>
#define LL long long
#define uLL unsigned long long
#define db double

using namespace std;
const int N=100+10;
int rd()
{
	int x=0,w=1;char ch=0;
	while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
	return x*w;
}
int n,p[N],dg[N];
vector<int> e[N];
vector<int>::iterator it;
void add(int x,int y){e[x].push_back(y),e[y].push_back(x),++dg[x],++dg[y];}
bool v[N];
int vv[N];
char cc[N];
void dfs(int o,int s,int lf)
{
	if(s<0) return;
	if(!lf)
	{
		for(int i=o;i<=n;++i)
		{
			s+=cc[i]=='('?1:-1;
			if(s<0) return;
		}
		for(int i=1;i<=n;++i) putchar(cc[i]);
		puts("");
		exit(0);
	}
	while(!vv[o])
	{
		s+=cc[o]=='('?1:-1;
		if(s<0) return;
		++o;
	}
	if(vv[o]==1)
	{
		cc[o]='(';
		dfs(o+1,s+1,lf-1);
		cc[o]=')';
	}
	else
	{
		int tt=vv[o],x=o;
		while(tt--) cc[x]='(',x=p[p[x]];
		dfs(o+1,s+1,lf-vv[o]);
		tt=vv[o],x=o;
		while(tt--) cc[x]=')',x=p[p[x]];
		tt=vv[o],x=p[o];
		while(tt--) cc[x]='(',x=p[p[x]];
		dfs(o+1,s-1,lf-vv[o]);
		tt=vv[o],x=p[o];
		while(tt--) cc[x]=')',x=p[p[x]];
	}
}

int main()
{
	n=rd();
	for(int i=1;i<=n;++i) p[i]=rd(),cc[i]=')',add(i,p[i]);
	for(int i=1;i<=n;++i)
		if(!v[i])
		{
			int x=i,cn=0;
			while(!v[x]) v[x]=1,++cn,x=p[x];
			vv[i]=cn/2;
		}
	dfs(1,0,n/2);
    return 0;
}
posted @ 2019-09-26 22:28  ✡smy✡  阅读(175)  评论(0编辑  收藏  举报