题目:解药毒药

题目描述

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

输入输出格式

输入格式:

输出格式:

输入输出样例


输入样例#1:

3
2
1 0 1
-1 1 0 



输出样例#1:

2


提示信息

  其实还有可能用尽了所有的药也不能将所有病治愈(真是不好意思嗬^^bb),那样的话你们只要写上“The patient will be dead.”就可以了。
  im:做不出来啊~~哇啊啊啊~~(暴走中)
  羽毛笔:哎呀~~im……来来吃药了。^^

题解

这是一道非常非常那啥的BFS题目(AWA~

这里给出一个BFS模板:参考:https://blog.youkuaiyun.com/ss123mlk/article/details/105671563

// 参数说明:start->起始转态;target:目标转态
int BFS(Node start, Node target) 
{
    Queue<Node> q; // 队列
    Set<Node> visited; // 是否访问过
    q.offer(start); // 将起点加入队列
    visited.add(start);
    int step = 0; // 记录扩散的步数

    while ( 队列不为空 ) {
        for (int i = 0; i < q.size(); i++) {
            Node cur = q.poll();
            if ( 判断是否到达目标状态 )
                return step;
            for (Node x : cur.adj())
                if ( 判断是否重复加入队列 )
                {
                    // 否, 将响相邻的节点加入队列
                    q.offer(x);
                    visited.add(x);
                }
        }
        // 更新步数
        step++;
    }
}

 接下来是代码:

#include<cstring>
#include<cstdio>
#include<iostream>
using namespace std;

struct node
{
    int step = 0;    // 搜索深度
    int b[11];
} list[1025];
int F[11];

bool hash[1025] = { false };
int a[1025][11];
int n, m;

int main()
{
	// 二进制转化表 
    for (int i = 0; i < 10; i++)
    {
        F[i + 1] = (1<<i);
    }
	
    cin >> n >> m;
    
    for (int i = 1; i <= m; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            cin >> a[i][j];
        }
    }
    
    int xx/*目标状态*/, tt/*目前的状态*/, head/*队列头*/, tail/*队列尾*/;
    xx = 0;
    for (int i = 1; i <= n; i++)
    {
        xx += F[i];
    }


    head = tail = 1;
    while (head <= tail)    // 队列不为空
    {
        for (int i = 1; i <= m; i++)
        {
            // 入队
            tail++;
            tt = 0;

            for (int j = 1; j <= n; j++)
            {
                // 计算新转态
                if (a[i][j] == 1) list[tail].b[j] = 1;
                if (a[i][j] == 0) list[tail].b[j] = list[head].b[j];    // 当为0时继承上一个的状态
                if (a[i][j] == -1) list[tail].b[j] = 0;

                if (list[tail].b[j] == 1) tt += F[j];   // 计算hash值
            }
            // 判断重复
            if (!hash[tt])
            {
                // 未添加到队列,添加相邻到队列
                hash[tt] = true;
                list[tail].step = list[head].step + 1;
                if (tt == xx)
                {
                    // 找到结果 -> 全都是1
                    cout << list[tail].step << endl;
                    return 0;
                }
            }
            else 
            {
                // 重复出队
                tail--;
            }
        }
        head++;
    }
    cout << "The patient will be dead." << endl;
    return 0;
}

上一篇: 题目:【交流七】找礼物
下一篇: 题目: 黑白棋游戏
ResCells
博客等级 码龄4年 191粉丝 26原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值