《算法竞赛-训练指南》第一章-1.7——UVa 11464

来源:互联网 发布:亚马逊关键词排名优化 编辑:程序博客网 时间:2024/05/24 06:52

这道题目非常的好,自己也遇到了很多类似的题目,都是TLE过去了,这是一种方法。自己应当掌握的

这种数据量不大但是枚举可以解决的问题。

这题的巧妙之处是这样的。

其一、如果枚举那些‘0’点,肯定会超时的。最多的‘0’是有15*15 = 225,那也就是需要枚举2^225次方。这肯定就超时了。所以,这是枚举方法的不对。

其二、重要的是你能否发现这里有个技巧,你枚举的是正确的结果,所以你只用枚举第一排就可以退出剩下的几排了的。所以,你只用枚举的是最多2^15次方。

其三,就是实现的时候千万要注意:第一、遇到枚举的不正确的时候,一定要及时终止,比如说,你枚举第一排的时候,原本是‘1’,而你枚举成了‘0’,那这种情况是肯定不成立的;第二、枚举好第一排的时候,也要依次求出其余的排,按照符合题意的求出,而如果期间求出的符合题意,但是与原本输入的不相符,那么这种枚举就可以不用做下去直接去掉了。


这些都弄好了之后就可以求出来,自己到底变了多少个‘0’成为1。


这道题目真的不错。

贴出代码:

#include <stdio.h>#include <string.h>#include <iostream>#include <string>#include <algorithm>using namespace std;const int INF = 0x3fffffff;int A[22][22];int B[22][22];int N;int min(int a, int b){return a < b ? a : b;}int check(int s){memset(B, 0, sizeof(B));for (int i = 0; i < N; i++){if (s & (1 << i)){B[1][i + 1] = 1; //将枚举的全部置成1. }else if (A[1][i + 1] == 1) // 这种情况的发生就是,原来是1,你却不把他置成1,这种情况是不允许发生的.即枚举错误. {return INF;}}int sum;for (int i = 2; i <= N; i++){for (int j = 1; j <= N; j++){sum = 0;sum += B[i - 2][j] + B[i - 1][j - 1] + B[i - 1][j + 1];//这是一个小技巧,通过下表从1开始,可以直接用通式求出sum. B[i][j] = sum % 2;if (A[i][j] == 1 && B[i][j] == 0){return INF;}}}int cnt = 0;for (int i = 1; i <= N; i++){for (int j = 1; j <= N; j++){if (A[i][j] != B[i][j]){cnt++;}}}return cnt;}int main(){int T;scanf("%d", &T);for (int cas = 1; cas <= T; cas++){scanf("%d", &N);memset(A, 0, sizeof(A));for (int i = 1; i <= N; i++){for (int j = 1; j <= N; j++){scanf("%d", &A[i][j]);}}int ans = INF;for (int i = 0; i < (1 << N); i++){ans = min(ans, check(i));}printf("Case %d: ", cas);if (ans == INF){printf("-1\n");}else{printf("%d\n", ans);}}//system("pause");return 0;} 




原创粉丝点击