51NOD 1400 序列分解
基准时间限制:1s 空间限制:131072
KB小刀和大刀是双胞胎兄弟。今天他们玩一个有意思的游戏。 大刀给小刀准备了一个长度为 $n$ 的整数序列。小刀试着把这个序列分解成两个长度为 $n/2$ 的子序列。
这两个子序列必须满足以下两个条件:
1.他们不能相互重叠。
2.他们要完全一样。
如果小刀可以分解成功,大刀会给小刀一些糖果。
然而这个问题对于小刀来说太难了。他想请你来帮忙。
Input
第一行给出一个T,表示T组数据。(1<=T<=5)
接下来每一组数据,输入共2行。
第一行包含一个整数n (2<=n<=40且为偶数)。
第二行给出n个整数a[0],a[1],a[2],…,a[n-1]表示大刀给小刀准备的序列。(-1,000,000,000<=a[i]<=1,000,000,000)
Output
如果小刀可以完成游戏,输出"Good job!!" (不包含引号),否则 输出"What a pity!" (不包含引号)。
Input示例
2
4
1 1 2 2
6
1 2 3 4 5 6
Output示例
Good job!!
What a pity!
分析:
暴力。DFS 递归地扩展出一棵解答树。节点(DFS)参数为 $(i, j, k)$ ,表示当前两子序列待确定 (active) 列中可
用(active) 的位置是 $k$ 。(其实 $k$ 是可有可无的参数,因为 $k = i+j-1$ ,但添上也无妨)代码中加上了一些剪枝。
不失一般性,可认为原序列的首元素属于第一个子序列,因此初始调用参数可设为 $( 2, 1, 2)$ 。
P.S. 考虑这个问题时,没想出非暴力的解法,只是看出:
如果原序列可分成两个相等的子列,那么原序列的首、尾一定也是子列的首、尾。
若有更好的解法,望在评论里告知。
1 #include<bits/stdc++.h> 2 using namespace std; 3 int a[50], N, x[50], y[50]; 4 bool dfs(int i, int j, int k){ 5 bool res; 6 if(k>N) return true; 7 if(i>N>>1){ 8 return a[k]==x[j]?y[j]=a[k], dfs(i, j+1, k+1):false; 9 } 10 if(j>N>>1){ 11 return a[k]==y[i]?x[i]=a[k], dfs(i+1, j, k+1):false; 12 } 13 if(i==j){ 14 x[i]=a[k]; 15 if(dfs(i+1, j, k+1)) return true; 16 y[j]=a[k]; 17 return dfs(i, j+1, k+1); 18 } 19 if(i>j){ 20 res = x[j]==a[k]?y[j]=a[k],dfs(i, j+1, k+1):false; 21 if(res) return res; 22 return x[i]=a[k],dfs(i+1, j, k+1); 23 } 24 if(j>i){ 25 res = y[i]==a[k]?x[i]=a[k],dfs(i+1, j, k+1):false; 26 if(res) return res; 27 return y[j]=a[k],dfs(i, j+1, k+1); 28 } 29 } 30 int main(){ 31 //freopen("in", "r", stdin); 32 int T; 33 scanf("%d", &T); 34 while(T--){ 35 scanf("%d", &N); 36 int res=0; 37 for(int i=1; i<=N; i++) scanf("%d", a+i), res^=a[i]; 38 if(res){ 39 puts("What a pity!"); 40 continue; 41 } 42 x[1]=a[1]; 43 puts(dfs(2, 1, 2)?"Good job!!":"What a pity!"); 44 } 45 return 0; 46 }