[noip模拟题]科技节 - 搜索 - 位运算优化
【问题描述】
一年一度的科技节即将到来。同学们报名各项活动的名单交到了方克顺校长那,结果校长一看皱了眉头:这帮学生热情竟然如此高涨,每个人都报那么多活动,还要不要认真学习了?!这样不行!……于是,校长要求减少一些活动,使每位学生只能参加一项(一名同学要参加某活动,必须已报名且该活动未被去掉)。当然,他也不希望哪位同学因此不能参加任何活动。他想知道自己的方案能否实行。
【输入】
输入文件名为scifest.in。
输入数据包括多组。
对于每组数据:
第一行两个正整数n和m,分别表示活动数和学生数。
接下来n行,每行m个为0或1的数。第i+1行第j列的数若为1,表示j同学报名参加活动i,否则表示j同学没有报名参加活动i。
【输出】
输出文件名为scifest.out。
对于每组数据输出一行,若校长方案可行则输出“Yes”,否则输出“No”。(均不包括引号)
【输入输出样例】
scifest.in |
scifest.out |
3 3 0 1 0 0 0 1 1 0 0 4 4 0 0 0 1 1 0 0 0 1 1 0 1 0 1 0 0 |
Yes No |
【数据范围】
对于20%的数据,n≤10,m≤200,数据组数≤10;
对于60%的数据,n≤16,m≤300,数据组数≤100;
对于100%的数据,n≤16,m≤300,数据组数≤1,000。
这题开始以为是用动态规划,后来发现n这么小应该使用搜索,后来经老师介绍,如果纯搜索+数组的话只能过6组数据,而加上二进制就可以全过
boolean数组其实既浪费内存又浪费时间,1个字节8个二进制位,而事实上储存true和false只用1个二进制位,所以用unsigned int类型的32个二进制位
来存储这些true和false的数据。其它都比较简单,直接就发代码了
Code
1 #include<iostream> 2 #include<fstream> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 #define k 32 7 typedef bool boolean; 8 ifstream fin("scifest.in"); 9 ofstream fout("scifest.out"); 10 boolean found; 11 int m,n; 12 int buf; 13 typedef struct myData{ 14 int peo; 15 unsigned int activities[10]; 16 }myData; 17 myData *s; 18 unsigned int ac[10]; 19 boolean cmp(const myData& a,const myData& b){ 20 return a.peo > b.peo; 21 } 22 boolean init(){ 23 if(!(fin>>n>>m)) return false; 24 s = new myData[(const int)(n + 1)]; 25 found = false; 26 for(int i = 0;i < n;i++){ 27 s[i].peo = 0; 28 memset(s[i].activities, 0, sizeof(s[i].activities)); 29 for(int j = 0;j < m;j++){ 30 fin>>buf; 31 if( buf == 1 ){ 32 s[i].peo++; 33 s[i].activities[j/k] += 1 << (j % k); 34 } 35 } 36 } 37 sort(s,s + n,cmp); 38 return true; 39 } 40 void free_MyPointer(){ 41 delete[] s; 42 } 43 void find(int vi,unsigned int *sed,int join){ 44 if(vi == n){ 45 if(join == m) found = true; 46 return ; 47 } 48 unsigned int t[10]; 49 boolean aFlag = true; 50 for(int i = 0;i <= m/k;i++){ 51 if((sed[i] & s[vi].activities[i]) != 0){ 52 aFlag = false; 53 break; 54 } 55 t[i] = sed[i] | s[vi].activities[i]; 56 } 57 if(aFlag) find(vi + 1, t, join + s[vi].peo); 58 if(!found) find(vi + 1, sed, join); 59 } 60 int main(){ 61 while(init()){ 62 find(0, ac, 0); 63 if(found) fout<<"Yes"<<endl; 64 else fout<<"No"<<endl; 65 free_MyPointer(); 66 } 67 return 0; 68 }