HDU_4725_思维建图+最短路

  • Post author:
  • Post category:其他



HDU 4725

  • 难点是如何将楼层转化到图中,
  • 用2个点将一个面(楼层)抽象出来,1个

    入点,1个出点
  • 一个面上的所有点都指向

    出点

    ,权值为0

  • 入点

    指向该面所有的点(除了出点),权值为0

  • 入点指向出点

    ,权值为

    0

    ,
  • 中间的楼层的出点分别指向

    上一层的入点



    下一层的入点

    ,权值为

    c

    .将所有楼层都连接起来
  • 没有最短路则

    dist[n] = MAX
  1. dij
#include <iostream>
#include <string.h>
#include <queue>
#include <vector>
#include <cmath>
using namespace std;
const int maxn = 3e5+5;
const int MAX = 0x3f3f3f3f;

vector<pair<int,int> > e[maxn];
int n,m,cost;
int dist[maxn];

int dij() {
	priority_queue<pair<int,int> > que;
	memset(dist,0x3f,sizeof dist);
	que.push( make_pair(0,1) );
	dist[1] = 0;
	while (!que.empty()) {
		int cur = que.top().second; que.pop();
		for (int i=0; i<e[cur].size(); i++) {
			int to = e[cur][i].first;
			int div = e[cur][i].second;
			if (dist[to] > dist[cur] + div) {
				dist[to] = dist[cur] + div;
				que.push( make_pair(-dist[to],to) );
			}
		}
	}
	return dist[n];
}

int main() {
//	freopen("a.txt","r",stdin);
	int times,k=0;
	scanf("%d",&times);
	while (times--) {
		scanf("%d%d%d",&n,&m,&cost);
		// 楼层抽象化成2个点,一个入点,一个出点
		int temp;
		for (int i=1; i<=n; i++) { //i代表点,temp是该点的楼层
			scanf("%d",&temp);
			e[temp*2+n-1].push_back( make_pair(i,0) ); // 入点指向平面的点
			e[i].push_back( make_pair(temp*2+n,0) ); // 平面中的点指向出点
		}
		// 每个点之间的边
		int from,to,div;
		for (int i=1; i<=m; i++) {
			scanf("%d%d%d",&from,&to,&div);
			e[from].push_back( make_pair(to,div) );
			e[to].push_back( make_pair(from,div));
		}
		// 当前层的 出点 与 相邻层的 入点 建边
		for (int i=1; i<=n; i++) {
			from = 2 * i + n; // 出点
			if (i > 1) {
				to = from - 3;
				// 该层的出点,到上一层的入点
				e[from].push_back( make_pair(to,cost) );
			}
			if (i < n) {
				to = from + 1;
				// 该层的出点,到下一层的入点
				e[from].push_back( make_pair(to,cost) );
			}
		}
		int ans = dij();
		if (ans == MAX) printf("Case #%d: -1\n",++k);
		else printf("Case #%d: %d\n",++k,ans);

		// 清除上一组数据
		for (int i=1; i<=3 * n; i++) e[i].clear();
	}
	return 0;
}
  1. spfa
#include <iostream>
#include <string.h>
#include <queue>
#include <vector>
#include <cmath>
using namespace std;
const int maxn = 3e5+5;
const int MAX = 0x3f3f3f3f;

vector<pair<int,int> > e[maxn];
int n,m,cost;
int dist[maxn];
bool vis[maxn];

int spfa() {
	queue<int> que;
	memset(vis,0,sizeof vis);
	memset(dist,0x3f,sizeof dist);
	que.push(1);
	dist[1] = 0; vis[1] = 1;
	while (!que.empty()) {
		int cur = que.front(); que.pop();
		vis[cur] = 0;
		for (int i=0; i<e[cur].size(); i++) {
			int to = e[cur][i].first;
			int div = e[cur][i].second;
			if (dist[to] > dist[cur] + div) {
				dist[to] = dist[cur] + div;
				if (!vis[to]) {
					vis[to] = 1;
					que.push(to);
				}
				
			}
		}
	}
	return dist[n];
}

int main() {
//	freopen("a.txt","r",stdin);
	int times,k=0;
	scanf("%d",&times);
	while (times--) {
		scanf("%d%d%d",&n,&m,&cost);
		// 楼层抽象化成2个点,一个入点,一个出点
		int temp;
		for (int i=1; i<=n; i++) { //i代表点,temp是该点的楼层
			scanf("%d",&temp);
			e[temp*2+n-1].push_back( make_pair(i,0) ); // 入点指向平面的点
			e[i].push_back( make_pair(temp*2+n,0) ); // 平面中的点指向出点
		}
		// 每个点之间的边
		int from,to,div;
		for (int i=1; i<=m; i++) {
			scanf("%d%d%d",&from,&to,&div);
			e[from].push_back( make_pair(to,div) );
			e[to].push_back( make_pair(from,div));
		}
		// 当前层的 出点 与 相邻层的 入点 建边
		for (int i=1; i<=n; i++) {
			from = 2 * i + n; // 出点
			if (i > 1) {
				to = from - 3;
				// 该层的出点,到上一层的入点
				e[from].push_back( make_pair(to,cost) );
			}
			if (i < n) {
				to = from + 1;
				// 该层的出点,到下一层的入点
				e[from].push_back( make_pair(to,cost) );
			}
		}
		int ans = spfa();
		if (ans == MAX) printf("Case #%d: -1\n",++k);
		else printf("Case #%d: %d\n",++k,ans);

		// 清除上一组数据
		for (int i=1; i<=3 * n; i++) e[i].clear();
	}
	return 0;
}



版权声明:本文为qq_43580151原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。