这道题最难的地方是当一种药和它的一个后续药品出现后,如何防止其他的后续药品在搜索中出现,因为搜索的时候是按位置顺序探测的,所以位置不是相邻的时候,从下一层回退回来并不知道前面已经有这样的状态。剪枝的条件应该还有,我这个代码还是很慢。
测试用例:
输入:
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->5
245
13
5
23
124
4
0
3
0
0
245
13
5
23
124
4
0
3
0
0
输出:
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->2
2354
4351
2354
4351
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->#include<iostream>
#include<vector>
#include<string>
#include<algorithm>
usingnamespacestd;
constintMAXSIZE=500;//最大药品数目
vector<vector<int>>medicVect;//记录每种药品的后续药
vector<vector<int>>answers;//记录搜索到的所有药方
vector<int>target;//当前药方
vector<int>answer;//当前解法
intn,p,nCount;
boolused[MAXSIZE];//药是否已经出现
intlimit[MAXSIZE];//若药品及其后续药出现了,则限制其他后续药再次出现
boolis_Succ(intx,inty)
{//判断y是不是x的后续药
boolresult=false;
inti;
for(i=0;i<medicVect[x].size();++i)
{
if(medicVect[x][i]==y)
{
result=true;
}
}
returnresult;
}
intis_one_pred(intx)
{//取x的唯一前驱药,若为则说明前驱药不唯一
intresult=0;
inti,k;
k=0;
for(i=0;i<n;++i)
{
if(is_Succ(i,x)==true)
{
if(k==0)
{
k=i;
}
else
{
returnresult;
}
}
}
result=k;
returnresult;
}
voidlimit_inc(intx)
{//把x的后续药都标记为不可以再使用
inti;
for(i=0;i<medicVect[x].size();++i)
{
++limit[medicVect[x][i]];
}
}
voidlimit_dec(intx)
{//撤销x后续药不可以再使用的标记
inti;
for(i=0;i<medicVect[x].size();++i)
{
--limit[medicVect[x][i]];
}
}
boolinit()
{
nCount=0;//解法数
answer.resize(p+1);
answer[0]=0;
inti,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]))
returnfalse;
}
}
}
//记录已经知道的药(被使用了,可不参与搜索)
for(i=1;i<=p;++i)
{
if(target[i]!=0)
{
used[target[i]]=true;
}
}
returntrue;
}
voidSolve(intcurPos)
{
inti,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]);
}
}
}
intmain()
{
inti,num;
cin>>n;
stringinput;
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::iteratorpos=input.begin();
do
{
stringtemp;
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>>::iteratoriter;
for(iter=answers.begin();iter!=answers.end();++iter)
{
intsize=iter->size();
for(i=1;i<size;++i)
{
cout<<(*iter)[i]<<"";
}
cout<<endl;
}
}
system("pause");
return0;
}
#include<vector>
#include<string>
#include<algorithm>
usingnamespacestd;
constintMAXSIZE=500;//最大药品数目
vector<vector<int>>medicVect;//记录每种药品的后续药
vector<vector<int>>answers;//记录搜索到的所有药方
vector<int>target;//当前药方
vector<int>answer;//当前解法
intn,p,nCount;
boolused[MAXSIZE];//药是否已经出现
intlimit[MAXSIZE];//若药品及其后续药出现了,则限制其他后续药再次出现
boolis_Succ(intx,inty)
{//判断y是不是x的后续药
boolresult=false;
inti;
for(i=0;i<medicVect[x].size();++i)
{
if(medicVect[x][i]==y)
{
result=true;
}
}
returnresult;
}
intis_one_pred(intx)
{//取x的唯一前驱药,若为则说明前驱药不唯一
intresult=0;
inti,k;
k=0;
for(i=0;i<n;++i)
{
if(is_Succ(i,x)==true)
{
if(k==0)
{
k=i;
}
else
{
returnresult;
}
}
}
result=k;
returnresult;
}
voidlimit_inc(intx)
{//把x的后续药都标记为不可以再使用
inti;
for(i=0;i<medicVect[x].size();++i)
{
++limit[medicVect[x][i]];
}
}
voidlimit_dec(intx)
{//撤销x后续药不可以再使用的标记
inti;
for(i=0;i<medicVect[x].size();++i)
{
--limit[medicVect[x][i]];
}
}
boolinit()
{
nCount=0;//解法数
answer.resize(p+1);
answer[0]=0;
inti,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]))
returnfalse;
}
}
}
//记录已经知道的药(被使用了,可不参与搜索)
for(i=1;i<=p;++i)
{
if(target[i]!=0)
{
used[target[i]]=true;
}
}
returntrue;
}
voidSolve(intcurPos)
{
inti,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]);
}
}
}
intmain()
{
inti,num;
cin>>n;
stringinput;
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::iteratorpos=input.begin();
do
{
stringtemp;
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>>::iteratoriter;
for(iter=answers.begin();iter!=answers.end();++iter)
{
intsize=iter->size();
for(i=1;i<size;++i)
{
cout<<(*iter)[i]<<"";
}
cout<<endl;
}
}
system("pause");
return0;
}