POJ 1511【Invitation Cards】最短路+堆优化

题目链接:http://poj.org/problem?id=1511

题目大意:求从起点到各个站点的最短路之和以及从各个站点回到起点的最短路之和。

1、从起点到各个站点的最短路一遍Dijkstra+堆优化即可。

2、从各个站点到起点的最短路应将各边反向然后转步骤1。

数据结构:

邻接表存储有向边(出边表):

struct vNode{//定义表节点 
	int v,w;//以v为弧头的定点编号和边的权值 
	vNode *next;//指向下一个邻接节点 
};
struct hNode{//定义定点类型 
	vNode *first;//指向第一个邻接点 
};
hNode g[maxn];//头节点表 
void insertEdge(hNode &p,int x,int y) {//插入一条边 
	vNode *q;
	q=new(vNode);
	q->v=x;
	q->w=y;
	q->next=p.first;
	p.first=q;
}

代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>
#define INF 0x3f3f3f3f
#define LL long long
using namespace std;
const int maxn=1000000+7;
int dis[maxn];
int vis[maxn];
int n,m;
int a[maxn],b[maxn],c[maxn];
struct Node{
	int u,step;//结构体中的成员 
	//u为顶点,step为源点到定点u的最短路径 
	Node(){};//构造函数 
	Node(int a,int sp){
		u=a;//参数传递,u为定点 
		step=sp;//参数传递,step为源点到顶点u的最短路径 
	}
	bool operator < (const Node& a)const {//重载<,按成员step最小值优先 
		return step>a.step;
	}
}; 
struct vNode{//定义表节点 
	int v,w;//以v为弧头的定点编号和边的权值 
	vNode *next;//指向下一个邻接节点 
};
struct hNode{//定义定点类型 
	vNode *first;//指向第一个邻接点 
};
hNode g[maxn];//头节点表 
void insertEdge(hNode &p,int x,int y) {//插入一条边 
	vNode *q;
	q=new(vNode);
	q->v=x;
	q->w=y;
	q->next=p.first;
	p.first=q;
}
LL Dijkstra(int s){
	LL ans=0;
	priority_queue<Node> q;//创建优先队列、最小值优先 
	q.push(Node(s,0));
	memset(vis,0,sizeof vis);
	for(int i=1;i<=n;i++){
		dis[i]=INF;//初始化所有距离为无穷大 
	}
	dis[s]=0;
	while(!q.empty()){
		Node it=q.top();//优先队列队头元素为最小值 
		q.pop();
		int t=it.u;
		if(vis[t]) continue;//说明已经找到了最短距离,该节点是队列里面的重复元素 
		vis[t]=1;
		vNode *p=g[t].first;
		while(p!=NULL){
			int v=p->v;
			int w=p->w;
			if(!vis[v]){//判断当前顶点的邻接点 
				if(dis[v]>dis[t]+w){//求距离当前顶点的每个点的最短距离,进行松弛操作 
					dis[v]=dis[t]+w;
					q.push(Node(v,dis[v]));//把更新后的最短距离压入优先队列 
				}
			}
			p=p->next;
		}
	}
	for(int i=1;i<=n;i++){
		ans+=dis[i];
		//printf("dis[%d]:%d\n",i,dis[i]);
	}
	return ans;
}
int main(){
	int t;
	scanf("%d",&t);
	while(t--){
		LL ans=0;
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;i++)
			g[i].first=NULL;
		for(int i=1;i<=m;i++){
			scanf("%d%d%d",&a[i],&b[i],&c[i]);
			insertEdge(g[a[i]],b[i],c[i]);
			//insertEdge(g[v],u,w);
		}
		ans=Dijkstra(1);
		for(int i=1;i<=n;i++)
			g[i].first=NULL;
		for(int i=1;i<=m;i++)
			insertEdge(g[b[i]],a[i],c[i]);//将边反转 
		ans+=Dijkstra(1);
		printf("%lld\n",ans);
	}
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37867156/article/details/81319763