题目
思路
⟨ i , p i ⟩ \lang i,p_i\rang ⟨i,pi⟩ 这些边构成很多环,环上相邻两点不同。说白了,每个环只有两种情况。
并不是高级算法,就是枚举。一开始以为是玄学搜索,没想到它的复杂度是严格的……
只需要注意到一点:二元环一定是靠左的为左括号,另一个为右括号。这是显然的,因为合法括号序列等价于任意前缀有 ( ( (左括号数量 ) ≥ ( )\ge( )≥(右括号数量 ) ) ) ,而这样固定二元环是没有任何负面作用的。
没有三元环,不然无解。题目中没有给出是否保证有解,这是题目描述的纰漏。但我告诉你,确实都有解,所以没有奇环。于是剩下的最小是四元环,所以复杂度 Θ ( 2 n 4 ) \mathcal \Theta(2^{\frac{n}{4}}) Θ(24n) ,而且可行性剪枝能够剪去很多。这是严格的复杂度啊!
代码
#include <cstdio>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdlib>
using namespace std;
typedef long long int_;
inline int readint(){
int a = 0; char c = getchar(), f = 1;
for(; c<'0'||c>'9'; c=getchar())
if(c == '-') f = -f;
for(; '0'<=c&&c<='9'; c=getchar())
a = (a<<3)+(a<<1)+(c^48);
return a*f;
}
template < typename T >
inline void getMax(T &a,const T &b){
(a < b) ? (a = b) : 0;
}
template < typename T >
inline void getMin(T &a,const T &b){
(b < a) ? (a = b) : 0;
}
const int MaxN = 105;
int n; // 基本信息:点的数量
int bel[MaxN]; // 属于哪一组
int k[MaxN]; // 对应于 bel 的系数
int tmp[MaxN]; // 每一组的系数
int val[MaxN]; // 目前的选择
bool check(){
for(int i=1,now=0; i<=n; ++i){
if(i == bel[i]) tmp[i] = 0;
val[i] = k[i]*val[bel[i]];
if(val[i] != 0){
now += val[i];
if(now < 0) return false;
continue; // 不管下面的
}
if(k[i]*tmp[bel[i]] < 0){ // 异号
if((-- now) < 0) // 绝对值变小
return false; // 判断效果
} else ++ now; // 否则增大
tmp[bel[i]] += k[i];
}
return true;
}
int now; // 整体作用于 dfs
void dfs(int t){
if(t == n+1){
for(int i=1; i<=n; ++i)
putchar(val[i] == 1 ? '(' : ')');
exit(0); // 直接 go away!
}
if(val[t]){
now += val[t], dfs(t+1);
now -= val[t]; return ;
}
val[t] = 1;
if(check()){
now += val[t], dfs(t+1);
now -= val[t];
}
val[t] = -val[t]; // 否则换花样
if(check()){
now += val[t], dfs(t+1);
now -= val[t];
}
val[t] = 0; // 不知道怎么办才好
}
int p[MaxN];
int main(){
srand(5201314);
n = readint();
for(int i=1; i<=n; ++i)
p[i] = readint();
for(int i=1; i<=n; ++i){
if(bel[i]) continue;
bel[i] = i, k[i] = 1;
for(int j=i; p[j]!=i; j=p[j]){
bel[p[j]] = i;
k[p[j]] = -k[j];
}
if(p[p[i]] == i) // 二元环
val[i] = 1, val[p[i]] = -1;
}
dfs(1); // 减少参数数量
return 0;
}