POJ - 1511 Invitation Cards(Dijkstra变形题)

题意:

给定一个有向图,求从源点到其他各点的往返最短路径和。且这个图有一个性质:任何一个环都会经过源点。

图中的节点个数范围:0~100w;

分析:

   我们先可以利用Dijkstra算法求解从源点到其余各点的最短距离,这样工作就完成了一半了。

那么如何求解从各点到源点的最短路呢?

   1. 我们可以循环n-1次,每次计算点i到其余各点的最短路,从中取出i到源点的最短路,这样我们就可以其余各点到源点的最短路。

       显然上述方法中存在大量冗余,显然针对题目的取值范围:0~100w,必定会超时的。如果你不信,可以试试。  

       按照上诉方法实践,超时的代码:

#include<cstdio>
#include<string.h>
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
#define maxn 1000000
#define inf 0x3f3f3f3f
typedef pair<int,int> P;
struct edge{
	int t;
	int c;
	edge(){	t=0,c=0;}
	edge(int tt,int cc){
		t=tt,c=cc;
	}
};
int dist[maxn];
vector<edge> map[maxn];
void dijkstra(int s,int n){
	priority_queue<P,vector<P>,greater<P> > Q;
	for(int i=1;i<=n;i++)
		dist[i]=inf;
	dist[s]=0;
	bool visited[maxn];
	memset(visited ,0,sizeof(visited));

	Q.push(P(0,s));
	while(!Q.empty()){
		int v=Q.top().second;
		Q.pop();
		if(visited[v])  continue;
		visited[v]=true;
		for(int i=0;i<map[v].size();i++){
			edge e=map[v][i];
			if(dist[e.t]>dist[v]+e.c){
				dist[e.t]=dist[v]+e.c;
				Q.push(P(dist[e.t],e.t));
			}
		}
	}
}
void init(int n){
	for(int i=0;i<=n;i++){
		map[i].clear();
	}
}
int main(){
	//freopen("in.txt","r",stdin);
	int cases;
	scanf("%d",&cases);
	for(int t=1;t<=cases;t++){
		int n,m;
		scanf("%d %d",&n,&m);
		init(n);
		while(m--){
			int a,b,c;
			scanf("%d %d %d",&a,&b,&c);
			map[a].push_back(edge(b,c));
		}
		dijkstra(1,n);
		int sum=0;
		for(int i=1;i<=n;i++)
			sum+=dist[i];
		for(int i=2;i<=n;i++){
			dijkstra(i,n);
			sum+=dist[1];
		}
		printf("%d\n",sum);
	}
}

2.经过别人题解指点,发现一个很好的方法。

首先,我们需要构造原图的反图。

原图为有向图,反图为建立在原图的基础之上,原图的边的源点为反图的终点,原图的边的终点为反图的源点。

总之,把原图的边的方向全部反转,就构成了反图。

在构建完反图后,我们再来对反图应用Dijkstra算法,源点为1.

接着,我们获得了从源点到其余各点的最短距离,注意我们的图是原图的反图,所以:

我们获得的其实是其余各点到源点的最短距离。

 

3.邻接表还是二维矩阵?

我们还需注意一个重要的问题:如何存储边信息?

按照题目中的数据范围0-100w,我们是无法开辟那么大的二维矩阵的,所以我们必须利用邻接表存储。

在这里我们使用vector实现。

 

源代码:

#include<cstdio>
#include<string.h>
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
#define maxn 1000001
#define inf 0x3f3f3f3f
typedef pair<int,int> P;
struct edge{
	int f;
	int t;
	int c;
	edge(){	f=0,t=0,c=0;}
	edge(int ff,int tt,int cc){
		f=ff,t=tt,c=cc;
	}
};
int dist[maxn];
vector<edge> map[maxn];
edge edges[maxn];
void dijkstra(int s,int n){
	priority_queue<P,vector<P>,greater<P> > Q;
	for(int i=1;i<=n;i++)
		dist[i]=inf;
	dist[s]=0;
	bool visited[maxn];
	memset(visited ,0,sizeof(visited));

	Q.push(P(0,s));
	while(!Q.empty()){
		int v=Q.top().second;
		Q.pop();
		if(visited[v])  continue;
		visited[v]=true;
		for(int i=0;i<map[v].size();i++){
			edge e=map[v][i];
			if(dist[e.t]>dist[v]+e.c){
				dist[e.t]=dist[v]+e.c;
				Q.push(P(dist[e.t],e.t));
			}
		}
	}
}
void init(int n){
	for(int i=0;i<=n;i++){
		map[i].clear();
	}
}
int main(){
	//freopen("in.txt","r",stdin);
	int cases;
	scanf("%d",&cases);
	for(int t=1;t<=cases;t++){
		int n,m;
		scanf("%d %d",&n,&m);
		init(n);
		for(int i=1;i<=m;i++){
			int a,b,c;
			scanf("%d %d %d",&a,&b,&c);
			edges[i]=edge(a,b,c);
			map[a].push_back(edge(a,b,c));
		}
		dijkstra(1,n);
		long long int sum=0;
		for(int i=1;i<=n;i++)
			sum+=dist[i];
		init(n);
		for(int i=1;i<=m;i++){
			edge tmp=edges[i];
			map[tmp.t].push_back(edge(tmp.t,tmp.f,tmp.c));
		}
		dijkstra(1,n);
		for(int i=1;i<=n;i++)
			sum+=dist[i];
		printf("%lld\n",sum);
	}
}

转载于:https://www.cnblogs.com/ZJUT-jiangnan/p/3935745.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值