【PAT】Dijkstra+最短路径种数(★)+输出路径+卡内存

来源:互联网 发布:淘宝注册账号打电话 编辑:程序博客网 时间:2024/06/02 05:38

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;elsecout<<"->";}} 
然后就因为这个【最短路径种数】和【内存超限】报错了。

修改之后是这样写的:

#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;elsecout<<"->";}} 
一开始以为【内存超限】是因为我没有把费用相同的路径合并计算(即第一个代码),但其实不是这个原因,而是我的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;elsecout<<"->";}} 


然后再仔细一看——哎呀原来内存超限的根本原因是优先队列根本就忘了用到“优先”了!( ̄_ ̄╬
于是,最完美的版本如下:

#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;elsecout<<"->";}} 
总结一下:考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<<" -> ";elsecout<<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<<" -> ";elsecout<<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<<" -> ";elsecout<<endl;}}
再比如:

https://www.patest.cn/contests/gplt/L2-001

#include<bits/stdc++.h>#define ll long longusing 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了……

0 0
原创粉丝点击