题目链接:
https://pintia.cn/problem-sets/994805342720868352/problems/994805347523346432
思路:
说多了都是泪,
Dijstra超时,采用dfs
利用map<pair<int,int>,int>,表示两个点和他们中间的地铁线号
每次更新最短路径即可
Dijstra WA Code
#include <iostream> #include<cstdio> #include<vector> #include<map> #include<cstring> #define MAX 0x3fffffff using namespace std; const int maxn=10005; vector<int> ed[maxn]; vector<int> path; int degre[maxn]; int dis[maxn],vis[maxn],num[maxn]; int loc[maxn],tot=0; int pre[maxn]; map<pair<int,int>,int> mp; void dfs(int v,int s,int t){if(v==-1) return;dfs(pre[v],s,t);tot++;path.push_back(v); } int main(int argc, char** argv) {int N;scanf("%d",&N);int cnt=0;memset(degre,0,sizeof(degre));for(int i=1;i<=N;i++){int M,start;scanf("%d %d",&M,&start);if(!vis[start]){loc[cnt++]=start;vis[start]=1;}for(int j=2;j<=M;j++){int x2;scanf("%d",&x2);if(!vis[x2]){loc[cnt++]=x2;vis[x2]=1;}ed[start].push_back(x2);ed[x2].push_back(start);mp[make_pair(start,x2)]=i;mp[make_pair(x2,start)]=i;degre[start]++;degre[x2]++;start=x2;}}int query;scanf("%d",&query);while(query--){//清零 int s,t;scanf("%d %d",&s,&t);if(s==t){cout<<0<<endl;continue;}for(int i=0;i<cnt;i++){dis[loc[i]]=MAX;vis[loc[i]]=0;num[loc[i]]=0;pre[loc[i]]=-1;}path.clear();dis[s]=0;tot=0;for(int i=0;i<cnt;i++){//n-1int mindis=MAX,ind=-1;for(int j=0;j<cnt;j++){if(!vis[loc[j]]&&(dis[loc[j]]<mindis)){mindis=dis[loc[j]];ind=j;}}if(ind==-1) break;vis[loc[ind]]=1;int now=loc[ind];for(int j=0;j<ed[now].size();j++){int next=ed[now][j];if(dis[next]>dis[now]+1){dis[next]=dis[now]+1;if(degre[next]>2) num[next]=num[now]+1;else num[next]=max(num[now],num[next]);pre[next]=now;}else if(dis[next]==dis[now]+1&&num[next]>num[now]+1){num[next]=num[now]+1;pre[next]=now; }}}dfs(t,s,t);printf("%d\n",tot-1);int line=0,pre=0;for(int j=1;j<path.size();j++){if(mp[make_pair(path[j-1],path[j])]!=line){if(line!=0) printf("Take Line#%d from %04d to %04d.\n",line,pre,path[j-1]);line=mp[make_pair(path[j],path[j-1])];//先保存前一个时刻的值,等下一个时刻来的时候再做处理 pre=path[j-1];}}printf("Take Line#%d from %04d to %04d.\n",line,pre,path[path.size()-1]);}return 0; }
正解:
参考自:https://www.liuchuo.net/archives/3850
#include <iostream> #include<cstdio> #include<vector> #include<map> #include<cstring> #define MAX 0x3fffffff using namespace std; const int maxn=10005; vector<int> ed[maxn],path,ans; int vis[maxn]; map<pair<int,int>,int> mp; int s,t; int minCnt=MAX,minTrans=MAX; int trans(const vector<int> &path){int line=0,tmp=0;for(int i=1;i<path.size();i++){if(mp[make_pair(path[i],path[i-1])]!=line) tmp++;line=mp[make_pair(path[i],path[i-1])];}return tmp; } void dfs(int v,int cnt){if(v==t){if(cnt<minCnt){minCnt=cnt;minTrans=trans(path);ans=path;}else if(cnt==minCnt&&trans(path)<minTrans){minTrans=trans(path);ans=path;}return; }for(int i=0;i<ed[v].size();i++){if(!vis[ed[v][i]]){vis[ed[v][i]]=1;path.push_back(ed[v][i]);dfs(ed[v][i],cnt+1);vis[ed[v][i]]=0;path.pop_back();}} } int main(int argc, char** argv) {int N;scanf("%d",&N);int cnt=0;for(int i=1;i<=N;i++){int M,start;scanf("%d %d",&M,&start);for(int j=2;j<=M;j++){int x2;scanf("%d",&x2);ed[start].push_back(x2);ed[x2].push_back(start);mp[make_pair(start,x2)]=i;mp[make_pair(x2,start)]=i;start=x2;}}int query;scanf("%d",&query);while(query--){//清零 memset(vis,0,sizeof(vis));path.clear();ans.clear();minCnt=MAX,minTrans=MAX;scanf("%d %d",&s,&t);vis[s]=1;path.push_back(s); dfs(s,0);printf("%d\n",ans.size()-1);int line=0,pre;for(int j=1;j<ans.size();j++){if(mp[make_pair(ans[j],ans[j-1])]!=line){if(line!=0) printf("Take Line#%d from %04d to %04d.\n",line,pre,ans[j-1]);//第一轮不做处理 line=mp[make_pair(ans[j],ans[j-1])];//先保存前一个时刻的值,等下一个时刻来的时候再做处理 pre=ans[j-1];}}printf("Take Line#%d from %04d to %04d.\n",line,pre,ans[ans.size()-1]);}return 0; }