科技节(位运算)
【问题描述】
一年一度的科技节即将到来。同学们报名各项活动的名单交到了方克顺校长那,结果校长一看皱了眉头:这帮学生热情竟然如此高涨,每个人都报那么多活动,还要不要认真学习了?!这样不行!……于是,校长要求减少一些活动,使每位学生只能参加一项(一名同学要参加某活动,必须已报名且该活动未被去掉)。当然,他也不希望哪位同学因此不能参加任何活动。他想知道自己的方案能否实行。
【输入】
输入文件名为scifest.in。
输入数据包括多组。
对于每组数据:
第一行两个正整数n和m,分别表示活动数和学生数。
接下来n行,每行m个为0或1的数。第i+1行第j列的数若为1,表示j同学报名参加活动i,否则表示j同学没有报名参加活动i。
【输出】
输出文件名为scifest.out。
对于每组数据输出一行,若校长方案可行则输出“Yes”,否则输出“No”。(均不包括引号)
【样例输入1】
3 3
0 1 0
0 0 1
1 0 0
4
0 0 0 1
1 0 0 0
1 1 0 1
0 1 0 0
【样例输出1】
Yes
No
位运算代码:
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
using namespace std;
long x[20][10];
long h[20];//一个活动的学生总数
long n,m;
long k=0;
int c;char yes=false;
void solve(long p,long qw[10],long per)//选第P个,前数组,完成的人数
{
if(yes==true)return ;
if(p==n)
{
if(per==m)
{
yes=true;
return ;
}
return ;
}
long t[10];
for(k=0;k<=9;k++)
{
if((qw[k]&x[p][k])>0)break;
t[k]=qw[k]|x[p][k];
}
if(k==10)solve(p+1,t,per+h[p]);
if(yes==false) solve(p+1,qw,per);
}
int main()
{
ios::sync_with_stdio(false);
freopen("scifest.in","r",stdin);
freopen("scifest.out","w",stdout);
while(cin>>n>>m)//活动数,学生数
{
memset(x,0,sizeof(x));
memset(h,0,sizeof(h));
yes=false;
for(int i=0;i<=n-1;i++)
{
h[i]=0;
for(int j=0;j<=m-1;j++)
{
cin>>c;
if(c==1)
{
x[i][j/31]+=1<<(j%31);
h[i]++;
}
}
}
for(int i=0;i<=n-2;i++)
for(int j=i+1;j<=n-1;j++)
if(h[i]<h[j])//降序
{
k=h[i];h[i]=h[j];h[j]=k;
for(int q=0;q<=9;q++)
{
k=x[i][q];x[i][q]=x[j][q];x[j][q]=k;
}
}
solve(0,x[19],0);
if(yes==true)cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
}
感想:此题一开始根本没想到用位运算,看到题后先想到的是搜索。如果用搜索的话,还要用排序将活动选的人多的排在前面降序,这样剪枝效果很好,我也没有想到。。。。以后看到这种0、1的题后,我应该先想一下能不能用位运算做(虽然掌握不熟练。)