您的位置:首页 > 其它

[JZOJ5029]围墙

2017-03-25 15:00 393 查看

题目大意

给定一个长度为n的排列{Pi}(∀i,Pi≠i),要求构造一种合法的括号序列,满足:

∙构造一个n个点的图,当第i个位置是左括号时,存在边(i,Pi),最后形成的图必须满足每个点度数为1。

输出任意一种方案即可,数据保证有解。

1≤n≤100

题目分析

显然我们先将所有(i,Pi)连上会形成若干个互不连通的简单环,一个简单环只要确定了一个点是左还是右就能确定整个环的状态。那么我们显然可以搜索加判断,因为每个环最小大小是2,所以复杂度是O(2n/2)。

考虑怎么优化,可以发现大小为2的环其实可以直接根据先后顺序确定填什么。那么我们直接特判掉大小为2的环,剩下的环最小大小是4(奇数显然无解),于是复杂度降为O(2n/4)。是不是很机智?

代码实现

#include <algorithm>
#include <iostream>
#include <cstdio>

using namespace std;

const int N=105;

int P
,fa
,rank
;
bool seq
,cet
;
int n;

int getfather(int son){return fa[son]==son?son:fa[son]=getfather(fa[son]);}

inline int merge(int x,int y)
{
if (rank[x]>rank[y]) swap(x,y);
fa[x]=y,rank[y]+=rank[x]==rank[y];
}

inline void go(int x){for (int y=P[x],c=seq[x];x!=y;c=seq[y]=c^1,cet[y]^=1,y=P[y]);}

bool dfs(int x,int sum)
{
if (sum<0) return 0;
if (x==n+1) return !sum;
if (!cet[x])
{
/*if (seq[x]=0,go(x),dfs(x+1,sum+(seq[x]?-1:1))) return 1;
go(x);
if (P[P[x]]==x) return 0;
if (seq[x]=1,go(x),dfs(x+1,sum+(seq[x]?-1:1))) return 1;
return go(x),0;*/
for (int c=0,y,z,cnt;c<2;++c)
{
for (cnt=1,z=seq[x]=c,y=P[x];x!=y;z=seq[y]=z^1,cet[y]=1,y=P[y],++cnt);
if (dfs(x+1,sum+(seq[x]?-1:1))) return 1;
if (cnt==2) return 0;
}
for (int y=P[x];x!=y;y=P[y],cet[y]=0);
return 0;
}else return dfs(x+1,sum+(seq[x]?-1:1));
}

int main()
{
freopen("wall.in","r",stdin),freopen("wall.out","w",stdout);
scanf("%d",&n);
for (int i=1;i<=n;++i) fa[i]=i;
for (int i=1;i<=n;++i)
{
scanf("%d",&P[i]);
int fx=getfather(i),fy=getfather(P[i]);
if (fx!=fy) merge(fx,fy);
}
dfs(1,0);
for (int i=1;i<=n;++i) putchar(seq[i]?')':'(');
printf("\n");
fclose(stdin),fclose(stdout);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: