POJ 3740
思路:二进制枚举,再用位运算来判断选的那些行是否满足每列只有一个1,(很神奇的位运算)。考虑最多16行,因此可以用一个int型(32位>16)的每个二进制位来表示每列状态,比如某列的第二行有个1,则int型数字里面第二个二进制位就为1,时间复杂度2^16*m,可以接受。这里存在一个问题就是怎么通过每列的状态(一个int型的数,设为col[j])来判断这一列是否含有一个1呢?可以这么做,令t
= col[j]&i(i表示枚举的行的二进制状态),这样就把枚举的行里面的1取了出来,如果t=0,说明枚举的这些行对应的某列里面一个1都不含,那么就不满足条件,如果t不等于0呢?那么还要考察这列里面是不是只含一个1,可以让t&(t-1),等于0就是一个1,否则不是!
#include<cstdio> #include<string> #include<cstring> #include<iostream> #include<algorithm> #define MAXN 333 using namespace std; int col[MAXN]; int main(){ int n, m, tmp; freopen("in.c", "r", stdin); while(~scanf("%d%d", &n, &m)){ int flag = 0; memset(col, 0, sizeof(col)); for(int i = 0; i < n; i ++){ for(int j = 0; j < m; j ++){ scanf("%d",&tmp); if(tmp) col[j] += (1 << i); if(i == n-1 && col[j] == 0) flag = 1; } } if(flag){printf("It is impossible\n"); continue;} for(int i = 1; i < (1 << n); i ++){ int tmp = 0; for(int j = 0; j < m; j ++){ int t = col[j] & i; if(t == 0 || (t & (t-1))) { tmp = 1; break; } } if(!tmp) {flag = 1; break; } } printf(flag == 0 ? "It is impossible\n":"Yes, I found it\n"); } return 0; }