https://www.patest.cn/contests/pat-a-practise/1087
在求最短路径种数的时候,是这样写的:
#include<bits/stdc++.h> using namespace std; int n,m,ed,a; string st,z,y; map<string,int> r; struct node{ string a; int b; }x[205]; int w[205][205]; int path[205]; int num[205]; int happy[205]; int cost[205]; int main(){ cin>>n>>m>>st; for(int i=0;i<n;++i){ for(int j=0;j<n;++j){ w[i][j]=100000000; } } x[0].a=st; r[st]=0; for(int i=1;i<n;++i){ cin>>x[i].a>>x[i].b; if(x[i].a=="ROM") ed=i; r[x[i].a]=i; } while(m--){ cin>>y>>z>>a; w[r[y]][r[z]]=a; w[r[z]][r[y]]=a; } for(int i=0;i<n;++i){ cost[i]=100000000; } priority_queue<int> q; q.push(0); cost[0]=0; int costs=100000000,happys=-1,nums=100000000,sum=-1,p; while(!q.empty()){ int fr=q.top(); q.pop(); if(fr==ed){ if(cost[fr]<costs|| (cost[fr]==costs&&happy[fr]>happys)|| (cost[fr]==costs&&happy[fr]==happys&&num[fr]<nums)){ costs=cost[fr]; happys=happy[fr]; nums=num[fr]; p=fr; } if(cost[fr]<costs) sum=1; else if(cost[fr]==costs) sum++; continue; } for(int i=0;i<n;++i){ if(cost[fr]+w[fr][i]<=cost[i]){ cost[i]=cost[fr]+w[fr][i]; if(happy[fr]+x[i].b>happy[i]|| (happy[fr]+x[i].b==happy[i]&&num[fr]+1<num[i])){ happy[i]=happy[fr]+x[i].b; num[i]=num[fr]+1; path[i]=fr; } q.push(i); } } } cout<<sum<<" "<<costs<<" "<<happys<<" "<<happys/nums<<endl; stack<int> st; st.push(ed); while(ed!=0){ ed=path[ed]; st.push(ed); } while(!st.empty()){ cout<<x[st.top()].a; st.pop(); if(st.empty()) cout<<endl; else cout<<"->"; } }然后就因为这个【 最短路径种数】和【内存超限】报错了。
修改之后是这样写的:
#include<bits/stdc++.h> using namespace std; int n,m,ed,a; string st,z,y; map<string,int> r; struct node{ string a; int b; }x[205]; int w[205][205]; int path[205]; int num[205]; int happy[205]; int cost[205]; int over[205]; int main(){ cin>>n>>m>>st; for(int i=0;i<n;++i){ for(int j=0;j<n;++j){ w[i][j]=100000000; } } x[0].a=st; r[st]=0; for(int i=1;i<n;++i){ cin>>x[i].a>>x[i].b; if(x[i].a=="ROM") ed=i; r[x[i].a]=i; } while(m--){ cin>>y>>z>>a; w[r[y]][r[z]]=a; w[r[z]][r[y]]=a; } for(int i=0;i<n;++i){ cost[i]=100000000; } priority_queue<int> q; q.push(0); cost[0]=0; over[0]=1; int costs=100000000,happys=-1,nums=100000000,sum=-1,p; while(!q.empty()){ int fr=q.top(); q.pop(); if(fr==ed){ if(cost[fr]<costs|| (cost[fr]==costs&&happy[fr]>happys)|| (cost[fr]==costs&&happy[fr]==happys&&num[fr]<nums)){ costs=cost[fr]; happys=happy[fr]; nums=num[fr]; p=fr; } if(cost[fr]<costs) sum=1; else if(cost[fr]==costs) sum++; continue; } for(int i=0;i<n;++i){ if(cost[fr]+w[fr][i]<=cost[i]){ if(happy[fr]+x[i].b>happy[i]|| (happy[fr]+x[i].b==happy[i]&&num[fr]+1<num[i])){ happy[i]=happy[fr]+x[i].b; num[i]=num[fr]+1; path[i]=fr; } if(cost[i]==cost[fr]+w[fr][i]){ over[i]+=over[fr]; } else{ q.push(i); over[i]=over[fr]; cost[i]=cost[fr]+w[fr][i]; } } } } cout<<over[ed]<<" "<<costs<<" "<<happys<<" "<<happys/nums<<endl; stack<int> st; st.push(ed); while(ed!=0){ ed=path[ed]; st.push(ed); } while(!st.empty()){ cout<<x[st.top()].a; st.pop(); if(st.empty()) cout<<endl; else cout<<"->"; } }一开始以为【内存超限】是因为我没有把费用相同的路径合并计算(即第一个代码),但其实不是这个原因,而是我的Dijkstra是优先队列nlogn版的……改成了n2的版本就过了。
#include<bits/stdc++.h> using namespace std; int n,m,ed,a; string st,z,y; map<string,int> r; struct node{ string a; int b; }x[205]; int w[205][205]; int path[205]; int num[205]; int happy[205]; int cost[205]; int over[205]; int main(){ cin>>n>>m>>st; for(int i=0;i<n;++i){ for(int j=0;j<n;++j){ w[i][j]=100000000; } } x[0].a=st; r[st]=0; for(int i=1;i<n;++i){ cin>>x[i].a>>x[i].b; if(x[i].a=="ROM") ed=i; r[x[i].a]=i; } while(m--){ cin>>y>>z>>a; w[r[y]][r[z]]=a; w[r[z]][r[y]]=a; } for(int i=0;i<n;++i){ cost[i]=100000000; } cost[0]=0; over[0]=1; int vis[205]={0}; int costs=100000000,happys=-1,nums=100000000,p; for(int nn=0;nn<n;++nn){ int fr; int minn=100000000; for(int i=0;i<n;++i){ if(vis[i]==1) continue; //这步千万别忘啊!! if(cost[i]<minn){ minn=cost[i]; fr=i; } } vis[fr]=1; //这步千万别忘啊!! if(fr==ed){ if(cost[fr]<costs|| (cost[fr]==costs&&happy[fr]>happys)|| (cost[fr]==costs&&happy[fr]==happys&&num[fr]<nums)){ costs=cost[fr]; happys=happy[fr]; nums=num[fr]; p=fr; } continue; } for(int i=0;i<n;++i){ if(vis[i]==1) continue; //这步千万别忘啊!! if(cost[fr]+w[fr][i]<=cost[i]){ if(cost[fr]+w[fr][i]<cost[i]|| (cost[fr]+w[fr][i]==cost[i]&&happy[fr]+x[i].b>happy[i])|| (cost[fr]+w[fr][i]==cost[i]&&happy[fr]+x[i].b==happy[i]&&num[fr]+1<num[i])){ happy[i]=happy[fr]+x[i].b; num[i]=num[fr]+1; path[i]=fr; } if(cost[i]==cost[fr]+w[fr][i]){ over[i]+=over[fr]; } else{ over[i]=over[fr]; cost[i]=cost[fr]+w[fr][i]; } } } } cout<<over[ed]<<" "<<costs<<" "<<happys<<" "<<happys/nums<<endl; stack<int> st; st.push(ed); while(ed!=0){ ed=path[ed]; st.push(ed); } while(!st.empty()){ cout<<x[st.top()].a; st.pop(); if(st.empty()) cout<<endl; else cout<<"->"; } }
然后再仔细一看——哎呀原来内存超限的根本原因是优先队列根本就忘了用到“优先”了!( ̄_ ̄╬
于是,最完美的版本如下:
#include<bits/stdc++.h> using namespace std; int n,m,ed,a; string st,z,y; map<string,int> r; struct node{ string a; int b; }x[205]; int w[205][205]; int path[205]; int num[205]; int happy[205]; int cost[205]; int over[205]; struct cmp{ bool operator()(const int &t1,const int &t2){ return cost[t1]>cost[t2]; //从小到小=大,与数组规则相反 } }; int main(){ cin>>n>>m>>st; for(int i=0;i<n;++i){ for(int j=0;j<n;++j){ w[i][j]=100000000; } } x[0].a=st; r[st]=0; for(int i=1;i<n;++i){ cin>>x[i].a>>x[i].b; if(x[i].a=="ROM") ed=i; r[x[i].a]=i; } while(m--){ cin>>y>>z>>a; w[r[y]][r[z]]=a; w[r[z]][r[y]]=a; } for(int i=0;i<n;++i){ cost[i]=100000000; } priority_queue<int,vector<int>,cmp> q; q.push(0); cost[0]=0; over[0]=1; int vis[205]={0}; //这步千万别忘啊!! int costs=100000000,happys=-1,nums=100000000,p; while(!q.empty()){ int fr=q.top(); q.pop(); if(vis[fr]==1) continue; //这步千万别忘啊!! vis[fr]=1; //这步千万别忘啊!! if(fr==ed){ if(cost[fr]<costs|| (cost[fr]==costs&&happy[fr]>happys)|| (cost[fr]==costs&&happy[fr]==happys&&num[fr]<nums)){ costs=cost[fr]; happys=happy[fr]; nums=num[fr]; p=fr; } continue; } for(int i=0;i<n;++i){ if(vis[i]==1) continue; //这步千万别忘啊!! if(cost[fr]+w[fr][i]<=cost[i]){ if(cost[fr]+w[fr][i]<cost[i]|| (cost[fr]+w[fr][i]==cost[i]&&happy[fr]+x[i].b>happy[i])|| (cost[fr]+w[fr][i]==cost[i]&&happy[fr]+x[i].b==happy[i]&&num[fr]+1<num[i])){ happy[i]=happy[fr]+x[i].b; num[i]=num[fr]+1; path[i]=fr; } if(cost[i]==cost[fr]+w[fr][i]){ over[i]+=over[fr]; } else{ q.push(i); over[i]=over[fr]; cost[i]=cost[fr]+w[fr][i]; } } } } cout<<over[ed]<<" "<<costs<<" "<<happys<<" "<<happys/nums<<endl; stack<int> st; st.push(ed); while(ed!=0){ ed=path[ed]; st.push(ed); } while(!st.empty()){ cout<<x[st.top()].a; st.pop(); if(st.empty()) cout<<endl; else cout<<"->"; } }总结一下:考PAT还是别写什么复杂的优先队列还是前向星了,节省时间增加正确率才是王道!
另外,PAT的最短路做来做去感觉好像都差不多。比如:
https://www.patest.cn/contests/pat-a-practise/1111
#include<bits/stdc++.h> using namespace std; struct node{ int a,b; }x[505][505]; int dis[505]; int spd[505]; int vis[505]; int path[505]; int path2[505]; int n,m,a,b,c,d,e,st,ed; int main(){ cin>>n>>m; for(int i=0;i<n;++i){ for(int j=0;j<n;++j){ x[i][j].a=x[i][j].b=100000000; } } while(m--){ cin>>a>>b>>c>>d>>e; if(c==1) x[a][b]={d,e}; else{ x[a][b]={d,e}; x[b][a]={d,e}; } } cin>>st>>ed; int tmp=ed; for(int i=0;i<n;++i){ dis[i]=100000000; spd[i]=100000000; } dis[st]=0;spd[st]=0; for(int nn=0;nn<n;++nn){ int minn=100000000,minn2=100000000,p=-1; for(int i=0;i<n;++i){ if(((dis[i]<minn)|| (dis[i]==minn&&spd[i]<minn2))&&vis[i]==0){ minn=dis[i]; minn2=spd[i]; p=i; } } vis[p]=1; if(p==ed) break; for(int i=0;i<n;++i){ if(vis[i]==1) continue; if(dis[p]+x[p][i].a<dis[i]|| (dis[p]+x[p][i].a==dis[i]&&spd[p]+x[p][i].b<spd[i])){ dis[i]=dis[p]+x[p][i].a; spd[i]=spd[p]+x[p][i].b; path[i]=p; } } } int ans=dis[ed]; for(int i=0;i<n;++i){ dis[i]=100000000; spd[i]=100000000; } ed=tmp; dis[st]=0;spd[st]=0; memset(vis,0,sizeof(vis)); for(int nn=0;nn<n;++nn){ int minn=100000000,minn2=100000000,p=-1; for(int i=0;i<n;++i){ if(((spd[i]<minn)|| (spd[i]==minn&&dis[i]<minn2))&&vis[i]==0){ minn=spd[i]; minn2=dis[i]; p=i; } } vis[p]=1; if(p==ed) break; for(int i=0;i<n;++i){ if(vis[i]==1) continue; if(spd[p]+x[p][i].b<spd[i]|| (spd[p]+x[p][i].b==spd[i]&&dis[p]+1<dis[i])){ spd[i]=spd[p]+x[p][i].b; dis[i]=dis[p]+1; path2[i]=p; } } } int u=0; while(ed!=st){ if(path[ed]!=path2[ed]){ u=1; break; } ed=path[ed]; } ed=tmp; stack<int> stk; if(u==0){ cout<<"Distance = "<<ans<<"; Time = "<<spd[ed]<<": "; stk.push(ed); while(ed!=st){ ed=path[ed]; stk.push(ed); } while(!stk.empty()){ cout<<stk.top(); stk.pop(); if(!stk.empty()) cout<<" -> "; else cout<<endl; } return 0; } cout<<"Distance = "<<ans<<": "; stk.push(ed); while(ed!=st){ ed=path[ed]; stk.push(ed); } while(!stk.empty()){ cout<<stk.top(); stk.pop(); if(!stk.empty()) cout<<" -> "; else cout<<endl; } ed=tmp; cout<<"Time = "<<spd[ed]<<": "; stk.push(ed); while(ed!=st){ ed=path2[ed]; stk.push(ed); } while(!stk.empty()){ cout<<stk.top(); stk.pop(); if(!stk.empty()) cout<<" -> "; else cout<<endl; } }再比如:
https://www.patest.cn/contests/gplt/L2-001
#include<bits/stdc++.h> #define ll long long using namespace std; // struct EDGE{ int u,v,w,next; }edge[500*500*2+5]; int head[500*500+5],pp; void init(){ pp=0; memset(head,0,sizeof(head)); } void add(int u,int v,int w){ edge[++pp]=(EDGE){u,v,w,head[u]}; head[u]=pp; } int n,m,a,b,c,d,e; int x[505]; int vis[505]; int dis[505]; int cost[505]; int path[505]; int times[505]; struct cmp{ bool operator()(const int &t1,const int &t2){ if(dis[t1]!=dis[t2]) return dis[t1]>dis[t2]; return cost[t1]<cost[t2]; } }; int main(){ cin>>n>>m>>a>>b; init(); for(int i=0;i<n;++i) cin>>x[i]; while(m--){ cin>>c>>d>>e; add(c,d,e); add(d,c,e); } for(int i=0;i<n;++i) dis[i]=100000000; priority_queue<int,vector<int>,cmp> q; q.push(a); dis[a]=0; cost[a]=x[a]; times[a]=1; while(!q.empty()){ int u=q.top(); q.pop(); if(vis[u]==1) continue; vis[u]=1; for(int i=head[u];i;i=edge[i].next){ int v=edge[i].v; int w=edge[i].w; if(vis[v]==1) continue; if(dis[u]+w<dis[v]) times[v]=times[u]; else if(dis[u]+w==dis[v]) times[v]+=times[u]; if(dis[u]+w<dis[v]){ dis[v]=dis[u]+w; cost[v]=cost[u]+x[v]; q.push(v); path[v]=u; } else if(dis[u]+w==dis[v]&&cost[u]+x[v]>cost[v]){ cost[v]=cost[u]+x[v]; q.push(v); path[v]=u; } } } cout<<times[b]<<" "<<cost[b]<<endl; stack<int> st; int tmp=b; while(path[b]!=a){ st.push(path[b]); b=path[b]; } cout<<a; while(!st.empty()){ cout<<" "<<st.top(); st.pop(); } if(b!=a) cout<<" "<<tmp; cout<<endl; }如果九月份再出这种类型的压轴题就完全可以pass了……