【题目解法】:
一.深搜加剪枝:
为什么n=2000的2^2000种情况可以用深搜?
1)我想应该是这题的条件比较强,必须保证已选的序列必须前面的部分完全相等才行,这是一个很强的剪枝条件,应该不用等到构造完序列而很快就能把不符合的剪掉;
2)另外题目中说只要找到任何一组就行了,所以一旦找到符合的就直接结束DFS,因此不会全部遍历枚2^2000种情况,这也是一个有效的剪枝条件;
3)另外还可以预先将第一个元素分在第一组,这是等价性剪枝,因为结果与分的第几组无关,而只与得到的两个序列有关。
二.题解分析
做题时,当时被wa懵了,没有深入分析到题解这一层,我来解释下题解:
分析:由题意一种颜色要么出现2次,要么出现4次;
a.如果一个序列中所有颜色仅出现2次。
假设当前位置第一次出现颜色a,我优先给第一个序列,第二个颜色a的位置有两种情况:1.在第一个颜色a的下一个,那我直
接给第二个序列,然后就这样推下去;2.在两个a之间还存在其他颜色,那这些颜色中不可能出现两种相同的颜色,否则就不满足构成两个相同的序列,所以都是单色的,这些颜
色凡是在a前面的给第二个序列,这肯定是它少于第一个序列的那部分,凡是之前没出现过的全部给第一个序列,然后到达第二个颜色a位置,给第二个序列,问题又进入了下一
轮,所以这样选下去总是可以的;按照我刚开始的错误做法是可行的。
b.如果一个序列中有一个或多个颜色出现4次。
那我能不能还按上述过程推理了呢?不能,因为情况a中两种相同颜色间必然不存在相同的颜色,而情况b可嵌套好多种颜色。情况变得更为复杂,所以需从别的角
度着手去分析。
我来说下为甚么没有a和d配对的情况,如果存在上面四种相同的颜色a1,a2,a3,a4;那我可以证明各种情况下都可以由a1和a4配对,a2和a3配对而形成的序列都可以由a1和a3配对,a2和a4配对或a1和a2配对,a3和a4配对等价的得到相同的序列,所以这种情况可被代替,只用考虑题解中的两种情况就可以了。
【解题回顾】:
1)这题刚开始看了题目想当然的一位很简单,只要用两个数组依次记下相同的成分就行了,if(flag1[arr[i]]==flag2[arr[i]]) flag1[arr[i]]++;
Else flag2[arr[i]]++;
看似没有任何问题,可当过不了豪哥的一组测试数据后,才动摇了,其实还是对题目理解不深,仅仅是觉得模棱两可以做时,就赶紧敲代码,争取少的罚时,其实多花点时间深刻透彻的理解题意才是最重要的。
2)在接下来虽然理解更进一层,可还是有些地方理解错误,导致又陷入无可奈何之中,但还是豪哥的测试数据挽救了我们,可见出测试数据的能力也是ACMer必须要具备的能力。(下面会具体讲)
3)最终中与完明白了题意:题目看似两个序列都有序,其实放在一起是没法按照有序直接做的!当我完全理解题意后,问题也就变得更加复杂了,一时还真想不出有效的解法来,听别人说深搜加剪枝可以,深搜我想在这种情况下作为最无奈的选择也就姑且一试了,结果真的就险过了。
【源程序】
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
#define Max(a,b) (a)>(b)?(a):(b)
#define Min(a,b) (a)<(b)?(a):(b)
int arr[2010];
int tag,n;
void dfs(char s[],int s1[],int p1,int s2[],int p2,int cur)
{
if(p1<=p2)
{
if(s1[p1]!=s2[p1])
return;
}
else
{
if(s1[p2]!=s2[p2])
return;
}
if(cur>n)
{
if(p1!=p2) return;
else
{
for(int i=1;i<=n/2;i++)
if(s1[i]!=s2[i])
return;
tag=1;
return;
}
}
else
{
int temp=s[cur];
s[cur]='0';
s1[++p1]=arr[cur];
dfs(s,s1,p1,s2,p2,cur+1);
if(tag==1) return;
s[cur]=temp;
--p1;
s[cur]='1';
s2[++p2]=arr[cur];
dfs(s,s1,p1,s2,p2,cur+1);
if(tag==1) return;
s[cur]=temp;
--p2;
}
}
int main(){
//freopen("iofile\\input.txt","r",stdin);
char s[2010];
int s1[2010],s2[2010];
int T,i;
scanf("%d",&T);
while(T--)
{
cin>>n;
for(i=1;i<=n;i++)
{
cin>>arr[i];
}
memset(s,0,sizeof(s));
memset(s1,0,sizeof(s1));
memset(s2,0,sizeof(s2));
tag=0;
s1[0]=1;
dfs(s,s1,1,s2,0,2);
printf("%s\n",s+1);
}
return 0;
}