搜索题---医生的药方

简介:
这道题最难的地方是当一种药和它的一个后续药品出现后,如何防止其他的后续药品在搜索中出现,因为搜索的时候是按位置顺序探测的,所以位置不是相邻的时候,从下一层回退回来并不知道前面已经有这样的状态。剪枝的条件应该还有,我这个代码还是很慢。

测试用例:

输入:

复制代码
5
2 4 5
1 3
5
2 3
1 2 4
4
0
3
0
0
复制代码
输出:

2
2 3 5 4
4 3 5 1
 

复制代码
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;

const int MAXSIZE = 500;//最大药品数目
vector<vector<int> > medicVect;//记录每种药品的后续药
vector<vector<int> >answers;//记录搜索到的所有药方

vector<int> target;//当前药方
vector<int> answer;//当前解法
int n,p,nCount;
bool used[MAXSIZE];//药是否已经出现
int limit[MAXSIZE];//若药品及其后续药出现了,则限制其他后续药再次出现

bool is_Succ(int x,int y)
{//判断y是不是x的后续药
    bool result = false;
    int i;
    for (i=0;i<medicVect[x].size();++i)
    {
        if (medicVect[x][i]==y)
        {
            result = true;
        }
    }
    return result;
}
int is_one_pred(int x)
{//取x的唯一前驱药,若为则说明前驱药不唯一
    int result = 0;
    int i,k;
    k = 0;
    for (i=0;i<n;++i)
    {
        if (is_Succ(i,x)==true)
        {
            if (k==0)
            {
                k = i;
            }
            else
            {
                return result;
            }
        }
    }
    result = k;
    return result;
}
void limit_inc(int x)
{//把x的后续药都标记为不可以再使用
    int i;
    for (i=0;i<medicVect[x].size();++i)
    {
        ++limit[medicVect[x][i]];
    }
}
void limit_dec(int x)
{//撤销x后续药不可以再使用的标记
    int i;
    for (i=0;i<medicVect[x].size();++i)
    {
        --limit[medicVect[x][i]];
    }
}
bool init()
{
    nCount = 0;//解法数
    answer.resize(p+1);
    answer[0] = 0;
    int i,j,k;
    //初始化限制条件,值均为
    for (i=0;i<MAXSIZE;++i)
    {
        limit[i] = 0;
    }
    for (i=2;i<=p-1;++i)
    {
        if (target[i]!=0)
        {
            //若有唯一的前驱药,则后续药不得再次出现,否则无解
            k = is_one_pred(target[i]);
            if (k==0)continue;
            for (j=i+1;j<=p;++j)
            {
                if(is_Succ(k,target[j]))
                    return false;
            }
        }
    }
    //记录已经知道的药(被使用了,可不参与搜索)
    for (i=1;i<=p;++i)
    {
        if (target[i]!=0)
        {
            used[target[i]] = true;
        }
    }
    return true;
}
void Solve(int curPos)
{
    int i,num;
    if (curPos>p)
    {//找到一种解
        //输出一个解法
        answers.push_back(answer);//保存当前解法
        nCount++;//解法数加
        return;
    }
    if (target[curPos]==0)
    {//当前位置药品未知,从前一药品的后续药中进行试探
        for (i=0;i<medicVect[answer[curPos-1]].size();++i)
        {
            num = medicVect[answer[curPos-1]][i];
            if (used[num]==false && limit[num]==0)
            {//符合条件,放置药品下去
                if (curPos>1)
                {//设置限制条件,防止后续药品出现
                    limit_inc(answer[curPos-1]);
                }
                answer[curPos] = num;//放入解法中
                used[num] = true;//被使用了
                Solve(curPos+1);//进入下一个位置的试探
                used[num] = false;//从上一层回来,重置状态
                if (curPos>1)
                {//恢复到原来的限制条件
                    limit_dec(answer[curPos-1]);
                }
            }
        }
    }
    else
    {//第curPos个位置的药已知
        if (curPos>1)
        {
            if (target[curPos-1]==0)
            {//判断是否满足前后继的关系
                if (!is_Succ(answer[curPos-1],target[curPos]))
                {
                    return;
                }
            }
        }
        if (curPos>1)
        {//设置限制条件,防止后续药品出现
            limit_inc(answer[curPos-1]);
        }
        answer[curPos] = target[curPos];//放入解法中
        Solve(curPos+1);//进入下一个位置的试探
        if (curPos>1)
        {//恢复到原来的限制条件
            limit_dec(answer[curPos-1]);
        }
    }
}
int main()
{
    int i,num;
    cin>>n;
    string input;
    getline(cin,input);
    //任何药都是号药的后续药
    vector<int> firstVect;
    for (i=0;i<n;++i)
    {
        firstVect.push_back(i+1);
    }
    medicVect.push_back(firstVect);
    //输入每一种药品的后续药
    for (i=0;i<n;++i)
    {
        vector<int> tmpVect;
        getline(cin,input);
        string::iterator pos = input.begin();
        do 
        {
            string temp;
            pos = find(input.begin(),input.end(),' ');//找到分隔符
            copy(input.begin(),pos,back_inserter(temp));
            num = atoi(temp.c_str());
            tmpVect.push_back(num);
            if (pos==input.end())
            {//最后一个数字了
                break;
            }
            else
            {
                input.erase(input.begin(),++pos);
            }
        } while (pos!=input.end());
        medicVect.push_back(tmpVect);
    }
    //输入给定的药方
    cin>>p;
    target.resize(p+1);
    for (i=1;i<=p;++i)
    {
        cin>>num;
        target[i] = num;
    }
    if (!init())
    {//无解
        cout<<"解法数目: "<<nCount<<endl;
    }
    else
    {
        Solve(1);
        cout<<nCount<<endl;
        vector<vector<int> >::iterator iter;
        for (iter = answers.begin();iter!=answers.end();++iter)
        {
            int size = iter->size();
            for (i = 1;i<size;++i)
            {
                cout<<(*iter)[i]<<" ";
            }
            cout<<endl;
        }
    }
    system("pause");
    return 0;
}
复制代码


本文转自Phinecos(洞庭散人)博客园博客,原文链接:http://www.cnblogs.com/phinecos/archive/2008/11/18/1336080.html,如需转载请自行联系原作者
目录
相关文章
|
Shell Linux 开发者
Windows下命令行使用说明
本文介绍了从Mac切换到Windows系统后,在使用命令行时遇到的换行符混乱、命令报错等问题,根源在于Windows Terminal可能随机加载PowerShell或CMD。文章梳理了CMD、PowerShell与Windows Terminal之间的关系,解释了为何相同界面下命令行为不一致,并给出CMD与PowerShell在换行符等使用上的区别,提醒用户注意环境差异,避免误操作。
1543 0
|
Android开发
无法唤起支付宝APP问题分析
商家在网页中调用支付宝提供的网页支付接口调起支付宝客户端内的支付模块,商家网页会跳转到支付宝中完成支付,支付完后跳回到商家网页内,最后展示支付结果。若无法唤起支付宝客户端,则在一定的时间后会自动进入网页支付流程。
10051 12
|
文字识别 API 语音技术
MacOS平台翻译OCR软件,双管齐下,还可自定义插件,为其添砖加瓦!
MacOS平台翻译OCR软件,双管齐下,还可自定义插件,为其添砖加瓦!
947 1
|
调度 网络架构 索引
NR PDSCH(三) TB size determination
谈TB size前,首先了解下PDSCH resource mapping,基站会通过RRC层配置的参数告知UE有一些时频资源(RB级/RE级)不能作为UE的PDSCH 资源使用,网络侧会对这些资源可能有特定用途,例如DSS场景中LTE作为NR 的inband部署时。用于发送RAR/OSI/Paging/MSG4/MSGB/SIB1 的PDSCH资源如果与SSB 的PRB overlap,overlap的PDSCH不能用于PDSCH 传输。
NR PDSCH(三) TB size determination
|
Linux Go Windows
gopacket使用
gopacket使用
|
Python
【从零学习python 】08.Python了解位运算符, 运算符优先级
【从零学习python 】08.Python了解位运算符, 运算符优先级
310 0
最全三大框架整合(使用映射)——DeptServiceImpl.java
最全三大框架整合(使用映射)——DeptServiceImpl.java
|
XML 设计模式 Java
《Spring 手撸专栏》第 6 章:气吞山河,设计与实现资源加载器,从Spring.xml解析和注册Bean对象
实现 1. 工程结构 2. 资源加载接口定义和实现 3. 包装资源加载器 4. Bean定义读取接口 5. Bean定义抽象类实现 6. 解析XML处理Bean注册 测试 1. 事先准备 2. 配置文件 3. 单元测试(资源加载) 4. 单元测试(配置文件注册Bean)
306 0
《Spring 手撸专栏》第 6 章:气吞山河,设计与实现资源加载器,从Spring.xml解析和注册Bean对象
|
Linux
LINUX下载编译libyuv
LINUX下载编译libyuv
507 0
|
存储 NoSQL 索引
MongoDB索引原理
MongoDB索引原理 为什么需要索引? 当你抱怨MongoDB集合查询效率低的时候,可能你就需要考虑使用索引了,为了方便后续介绍,先科普下MongoDB里的索引机制(同样适用于其他的数据库比如mysql)。 mongo-9552:PRIMARY> db.person.find() { "_