Silver Cow Party-Dijikstra(队列优化+路径反转)-逆向思维好题

题意:
给你一张有向图,要你求其他点到目标点x并且从目标点返回出发点的距离最小值的最大值。
思路:
我们学的是单源最短路,所以算其他点到目标点的距离不太现实,我们不妨转换视角,来个逆向思维,从其他点到目标点相当于把有向图反转后,从目标点到其他点。这样就可以解决去的问题,回的问题就是常规思路。所以先算回的最短路,然后路径反转,算去的最短路,然后两者相加就是往返最小值。最后比较即可。
这里我写了两个版本,一个是优先队列优化的,还有一个就是没有优化的。
优先队列优化的版本

AC code:
#include<iostream>
#include<cstdio>
#include<vector>
#include<bitset>
#include<stack>
#include<set>
#include<queue>
#include<map>
#include<cmath>
#include<string>
#include<cstring>
#include<ctime>
#include<fstream>
#include<cstdlib>
#include<algorithm>

using namespace std;

//typedef  pair<int, int> pii;
#define pii pair<int,int>
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define per(i,a,b) for(int i=a;i<=b;i++)
#define rep(i,a,b) for(int i=a;i>=b;i--)
#define all(x) x.begin(),x.end()
#define PER(i,x) for(auto i=x.begin();i!=x.end();i++)
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
typedef long long LL;
const double eps=1.0e-5;
const int maxn=1e3 + 10;
int dx[4] = {0,0,-1,1};
int dy[4] = {1,-1,0,0};
int n = 0,m = 0,x = 0; 
int adj[maxn][maxn];
int d1[maxn],d2[maxn];
bool used[maxn];
struct cmp{//cmp类型,然后重新定义比较方式 
	bool operator()(const pii a,const pii b){
		return a.second > b.second;//second小值优先 
	}
};
void dijikstra(int s,int* dist){
	fill(used,used+maxn,false);
	fill(dist,dist+maxn,INF);
	priority_queue<pii,vector<pii>,cmp > que;
	dist[s] = 0;//初始值设置 
	que.push(pii(s,0));
	while(!que.empty()){
		pii p = que.top();que.pop();//从未访问过的节点中选取距离远点最短的(更新距离的那些点) 
		int u = p.first,d = p.second;
		if(dist[u] < d || used[u] == true){//如果一直最小值比d小,或者已经访问过,就直接跳过 
			continue;
		}
		for(int i = 1;i <= n;++i){//更新周围点的最短路径 
			used[u] = true;
			if(dist[i] > dist[u] + adj[u][i] && used[i] == false){
				dist[i] = dist[u] + adj[u][i];
				que.push(pii(i,dist[i]));
			}
		}
	} 
}
int main(){
	#ifndef ONLINE_JUDGE
		//freopen("a.txt","r",stdin);
	#endif
	while(~scanf("%d %d %d",&n,&m,&x)){
		fill(adj[0],adj[0] + maxn*maxn,INF);
		
		per(i,1,m){
			int a = 0,b = 0,t = 0;
			scanf("%d %d %d",&a,&b,&t);
			adj[a][b] = t;
		}
		
		dijikstra(x,d1);
		per(i,1,n){//路径反转 
			per(j,i+1,n){//j要从i+1开始,否则反转两次,相当于没变化
				swap(adj[i][j],adj[j][i]);
			}
		}
	
		dijikstra(x,d2);
		int maxv = 0;
		per(i,1,n){
			if(d1[i] != INF && d2[i] != INF){//必须加上这个判断条件 
				maxv = max(maxv , d1[i] + d2[i]);
			}
		}
		printf("%d\n",maxv);
	}
	
	return 0; 
}

未用优先队列优化的版本:

AC code:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define INF 1e8
using namespace std;
const int maxn = 1000 + 10;
int vis[maxn];
int d[maxn],d1[maxn];
int map[maxn][maxn];
int n = 0,m = 0,x = 0;
void dijikstra(int s){
	d[s] = 0;
	while(true){
		int v = -1;
		for(int i = 1;i <= n;++i){
			if(vis[i] == false && (v == -1 || d[i] < d[v])){
				v = i;
			}
		}
		if(v == -1){
			break;
		}
		vis[v] = true;
		
		for(int i = 1;i <= n;++i){
			if(vis[i] == false && (d[v] + map[v][i]) < d[i]){
				d[i] = d[v] + map[v][i];
			}
		}
	}
}
void init(){
	fill(d,d+maxn,INF);
	fill(vis,vis+maxn,false);
	fill(map[0],map[0]+maxn*maxn,INF);
}
void traverse(){//路径反转 
	for(int i = 1;i <= n;++i){
		for(int j = i+1;j <= n;++j){//j不能从1开始,否则反转两次,相当于没变化 
			swap(map[i][j],map[j][i]);
		}
	}
}
int main(){
	scanf("%d %d %d",&n,&m,&x);
	init();
	for(int i = 0;i < m;++i){
		int a = 0,b = 0,w = 0;
		scanf("%d %d %d",&a,&b,&w);
		map[a][b] = w;
	}
	dijikstra(x);
	for(int j = 1;j <= n;++j){//储存第一次的运算结果,并且还原d,vis数组 
		d1[j] = d[j];
		d[j] = INF;
		vis[j] = false;
	}
	traverse();
	dijikstra(x);
	int maxv = 0;
	for(int j = 1;j <= n;++j){
		if(d[j] + d1[j] > maxv){
			maxv = d[j] + d1[j];
		}
	}
	printf("%d\n",maxv);
	return 0;
}
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值