搜索题---医生的药方

来源:互联网 发布:在js弹出窗口jsp 编辑:程序博客网 时间:2024/04/28 11:57

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

测试用例:

输入:

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;
}
原创粉丝点击