Unshuffle(深搜加剪枝-hdu4665)

 

【题目解法】:

一.深搜加剪枝:

为什么n=20002^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;
}


 

posted on 2013-08-11 09:27  Gddxz  阅读(249)  评论(0编辑  收藏  举报

导航