vijos_1026 毒药?解药?

题目:

  羽毛笔和im是抽签到同一个考场的,她们突然闻到一阵刺鼻的化学试剂的气味。
  机灵鼠:(头都不抬)你们是考生么?还在门口磨蹭什么?快进来帮我忙!!……怎么还不进来?你们拖赛,拖赛,把你们的青春都拖掉赛……
  im:开…开策了
  羽毛笔:哎呀 ~ ~机灵鼠大人要我们帮什么忙?^^
  机灵鼠:你们看这里的这些药,都是我研制的对付各种症状的解药。可是我一个不小心,每种药都小小地配错了一点原料,所以这些药都有可能在治愈某些病症的同时又使人患上某些别的病症……(im:那…那是解药还是毒药啊?!)……经过我天才的努力(背景:我是天才!!),终于弄清了每种药的具体性能(路人甲:那是你自己配的吗?-_-),我会把每种药能治的病症和能使人患上的病症列一张清单给你们,然后你们要根据这张清单找出能治愈所有病症的最少药剂组合……顺便说一声,病症的数目不超过10种(小呆:偶是好人吧^^),我的药是用不完的,就是说每种药剂都可以被重复使用。给你们的单子里第一行是病症的总数n,第二行是药剂的种类m(0<m<=100),以下有m行,每行有n个数字用空格隔开,文件的第i+2行的n个数字中,如果第j个数为1,就表示第i种药可以治愈病症j(如果患有这种病的话则治愈,没有这种病则无影响),如果为0表示无影响,如果为-1表示反而能使人得上这种病(无病患上,有病无影响)。我制的药任何两种性能都不同。你们只要给我用的最少的药剂数就可以了。

思路:

  二进制保存得病情况,广搜求答案,难度不大

代码:

#include <bits/stdc++.h>
using namespace std;
int ill[105][11],n,m;
bool vis[(1<<10)+5];
struct Node{
    int a,d;
};
int bfs(){
    int t=0;
    queue<Node> q;
    for(int i=1;i<=n;i++)
        t+=(1<<i);
    q.push((Node){t,0});
    vis[t]=true;
    while(!q.empty()){
        Node a=q.front();
        q.pop();
        if(a.a==0)
            return a.d;
        for(int i=1;i<=m;i++){
            int b=a.a;
            for(int j=1;j<=n;j++){
                if(ill[i][j]==-1){
                    if(((b>>j)&1)==0)
                        b+=(1<<j);
                }
                else if(ill[i][j]==1){
                    if(((b>>j)&1)==1)
                        b-=(1<<j);
                }
            }
            if(!vis[b]){
                q.push((Node){b,a.d+1});
                vis[b]=true;
            }
        }
    }
    cout<<"The patient will be dead."<<endl;
    return -1;
}
int main(){
    int ans;
    ios::sync_with_stdio(false);
    cin>>n>>m;
    for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++)
            cin>>ill[i][j];
    if((ans=bfs())!=-1)
        cout<<ans<<endl;
    return 0;
}