科技节(位运算)

【问题描述】

      一年一度的科技节即将到来。同学们报名各项活动的名单交到了方克顺校长那,结果校长一看皱了眉头:这帮学生热情竟然如此高涨,每个人都报那么多活动,还要不要认真学习了?!这样不行!……于是,校长要求减少一些活动,使每位学生只能参加一项(一名同学要参加某活动,必须已报名且该活动未被去掉)。当然,他也不希望哪位同学因此不能参加任何活动。他想知道自己的方案能否实行。

【输入】

      输入文件名为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的题后,我应该先想一下能不能用位运算做(虽然掌握不熟练。)

原文地址:https://www.cnblogs.com/937337156Zhang/p/5675239.html