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

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了……

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值