思路:用vector数组存每个点的课链接点,一个数字存两点间的路段属于哪个公司
tmp是暂时存现在路线,ans是保存最优路线
vis是记录该点有没有访问过,题目说存在圈,所以用其防止重复点
dfs暴搜,如果现在路线好于历史最优路线,则ans=tmp
tmp和ans存点的时候按:点——公司——点.......——公司——点 的方式存,打印是先提取第一个,之后两个两个遍历,取公司、点,末点就是下一个始点
//还原现场,非公司vis
#include<bits/stdc++.h>
using namespace std;
const int N=1e4+10,Max=0x3f3f3f3f;
int cpy[N][N],n,m,k,a,b;
vector<int> ma[N],tmp,ans;
int mincs,minps;
int vis[N];
void dfs(int p,int ps,int c,int cs){//当前站点,当前站点sum,当前公司no,当前转公司sum
if(p==b){
tmp.push_back(c), tmp.push_back(p);//公司,当前站点
if(ps<minps) ans=tmp, minps=ps, mincs=cs;
else if(ps==minps&&cs<mincs) ans=tmp, minps=ps, mincs=cs;
tmp.pop_back(), tmp.pop_back();
return ;
}
for(auto i:ma[p]){
if(vis[i]==0){
if(cpy[p][i]!=c){//公司不同
if(c!=-1) tmp.push_back(c), tmp.push_back(p);//pre公司,和下一站点(中转站)
vis[i]=1;
dfs(i,ps+1,cpy[p][i],cs+1);
if(c!=-1)tmp.pop_back(), tmp.pop_back(), vis[i]=0;//还原现场
}else{
vis[i]=1;
dfs(i,ps+1,c,cs);
vis[i]=0;
}
}
}
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d%d",&m,&a);
for(int j=1;j<m;j++){
scanf("%d",&b);
ma[a].push_back(b), ma[b].push_back(a), cpy[a][b]=cpy[b][a]=i;
a=b;
}
}
scanf("%d",&k);
for(int i=0;i<k;i++){
scanf("%d%d",&a,&b);
mincs=minps=Max;
memset(vis,0,sizeof vis);
ans.clear(), tmp.clear();
vis[a]=1, tmp.push_back(a);
dfs(a,1,-1,0);
if(ans.size()){
printf("%d\n",minps-1);
int f=*ans.begin(),e,cpyno;
ans.erase(ans.begin());
while(ans.size()){
cpyno=*ans.begin(); ans.erase(ans.begin());
e=*ans.begin(); ans.erase(ans.begin());
printf("Go by the line of company #%d from %04d to %04d.\n",cpyno,f,e);
f=e;
}
}else{
puts("Sorry, no line is available.");
}
}
return 0;
} 这里完整的还原现场十分重要
if(c!=-1) tmp.push_back(c), tmp.push_back(p);//pre公司,和下一站点(中转站) vis[i]=1; dfs(i,ps+1,cpy[p][i],cs+1); if(c!=-1)tmp.pop_back(), tmp.pop_back(), vis[i]=0;//还原现场
这里由于第一个只给站点,没有线段不存在公司,所以先传c=-1
当时下面没有if(c!=0) 调了我两天非公司忘记设vis

京公网安备 11010502036488号