题目来源:http://poj.org/problem?id=1063
题目大意:
有一种游戏如图所示。一个填满黑白球的转盘,它可以有两种操作,一种是将大转盘顺时针旋转,所有球的位置顺时针挪一位,另一种是转动小转盘,使位于小转盘处的三个小球颠倒位置。游戏的目标是达到下面的图片所示的状态,黑球与白球都处在连续的位置上。
写一个程序判断给出的球序列是否可能通过上述的两种操作达到目标序列。
输入:第一行为测试用例数T。每个用例第一个数为小球的数目n, 接下来是n个0和1组成的序列,每个数字用空格隔开,0表示白球,1表示黑球。n的值在10到30之间。
输出:如可能达到目标,输出一行“YES”, 否则“NO”
Sample Input
2 18 0 0 1 0 1 1 1 1 0 1 0 0 1 0 0 0 0 1 14 1 1 0 0 1 1 1 0 0 1 1 0 1 0
Sample Output
YES NO
观察和琢磨上面的两种对于球的操作,我们可以发现,其实规则等价于可以把任意三个相邻的三个球位置颠倒。考虑两种情况:
1. 球的总数为偶数,那么奇数位的球永远到不了偶数位上,反之亦然。
2. 球的总数为奇数,那么任意一个球都可以到达其它任意一个位置上,这种情况下总可以达到目标状态。
再考虑球总数为偶数时,实际上可以把操作对球颜色顺序的影响分离为对奇数位上球的影响和对偶数位球的影响。我们想象把所有偶数位的球固定,通过旋转可以调换奇数位上相邻的球,通过不断的调换可以把奇数位上黑球调至相邻位置。同样我们可以把偶数位上的黑球调至连续的位置。接下来还要考虑何种情况下才能使整个大转盘上的球可以达到不存在黑白相间的情况。答案是:奇数位上的黑球个数与偶数位上黑球的个数相差不超过1. 这就是球总数为偶数时能达到目标状态的充要条件。
附上两个版本的代码。(直观版和技巧版)
1 //////////////////////////////////////////////////////////////// 2 // POJ1063 Flip and Shift 3 // Memory: 208K Time : 16MS 4 // Language : C++ Result : Accepted 5 //////////////////////////////////////////////////////////////// 6 7 #include <iostream> 8 9 using namespace std; 10 11 int even_black, odd_black; 12 int buf, cnt; 13 14 int main(void) { 15 int T; 16 cin >> T; 17 for (int case_id = 1; case_id <= T; ++case_id) { 18 cin >> cnt; 19 even_black = odd_black = 0; 20 for (int i = 0; i < cnt; ++i) { 21 cin >> buf; 22 if (buf == 1) { 23 if (i % 2 == 1) { 24 ++odd_black; 25 } else { 26 ++even_black; 27 } 28 } 29 } 30 if (cnt % 2) { //总球数为奇 31 cout << "YES" << endl; 32 } else if (odd_black - even_black > 1 || odd_black - even_black < -1) { 33 cout << "NO" << endl; 34 } else { 35 cout << "YES" << endl; 36 } 37 } 38 return 0; 39 }
1 //////////////////////////////////////////////////////////////// 2 // POJ1063 Flip and Shift 3 // Memory: 208K Time : 0MS 4 // Language : C++ Result : Accepted 5 //////////////////////////////////////////////////////////////// 6 7 #include <iostream> 8 9 using namespace std; 10 11 int r[2]; 12 int buf, cnt; 13 14 int main(void) { 15 int T; 16 17 cin >> T; 18 for (int case_id = 1; case_id <= T; ++case_id) { 19 cin >> cnt; 20 r[0] = r[1] = 0; 21 for (int i = 0; i < cnt; ++i) { 22 cin >> buf; 23 r[i % 2] += buf; 24 } 25 cout << (cnt % 2 || r[1] - r[0] < 2 && r[1] - r[0] > -2 ? "YES" : "NO") << endl; 26 } 27 return 0; 28 }