WHUST 2017 Div.2 Day 15 [2017-08-06](图论八题)

有1~N一共N个结点,每个结点都有一头奶牛,

每只奶牛都打算到结点X(1<=X<=N)来参加派对,

并且在派对结束后回到原来的结点,

每只奶牛都选择最短的路程,

一共有M条单向的路,每条路通过的时间为Ti,(单向有权)

(1 ≤ N ≤ 1000)    (1 ≤ M ≤ 100,000)    (1 ≤ Ti ≤ 100)

问:来回的路程最长的奶牛经过的总路程为多少?

单源最短路(SSSP)问题的变种,“回家”即为从X到各点的最短路,“前往派对”即为将所有道路取反后,从X到各个点的最短路
比较稀疏的图,用Dijkstra模板即可

AC-Code (C++)

Time: 47 ms  Memory: 1060 kb

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#include<stack>
#include<string>
#include<vector>
#include<functional>
using namespace std;


const int maxn = 1005;
const int maxm = 100005;
const int inf = 1000000000;
int N, M, X;		//结点数,道路数,原点
struct Edge
{
	int from, to, dist;
	Edge(int u, int v, int d) :from(u), to(v), dist(d){}
};
vector<Edge> edges_1;		//存储正边
vector<int> G_1[maxn];
vector<Edge> edges_2;		//存储反边
vector<int> G_2[maxn];
bool done[maxn];		//是否已被访问
int d_1[maxn];		//到原点的距离
int d_2[maxn];		
typedef pair<int, int> pii;
int ans = -1;


void AddEdge_1(int from, int to, int dist)
{
	edges_1.push_back(Edge(from, to, dist));
	int m = edges_1.size();
	G_1[from].push_back(m - 1);
}


void AddEdge_2(int from, int to, int dist)
{
	edges_2.push_back(Edge(from, to, dist));
	int m = edges_2.size();
	G_2[from].push_back(m - 1);
}


void dijkstra_1(void)		//从原点到各点
{
	priority_queue<pii, vector<pii>, greater<pii> >Q;
	for (int i = 1; i <= N; i++)
		d_1[i] = inf;
	d_1[X] = 0;
	memset(done, 0, sizeof(done));
	Q.push(pii(0, X));
	while (!Q.empty())
	{
		pii x = Q.top();
		Q.pop();
		int u = x.second;		//u为当前结点的编号
		if (done[u])
			continue;
		done[u] = true;
		for (int i = 0; i < G_1[u].size(); i++)
		{
			Edge& e = edges_1[G_1[u][i]];
			if (d_1[e.to]>d_1[u] + e.dist)
			{
				d_1[e.to] = d_1[u] + e.dist;
				Q.push(pii(d_1[e.to], e.to));
			}
		}
	}
}


void dijkstra_2(void)		//从各点到原点
{
	priority_queue<pii, vector<pii>, greater<pii> >Q;
	for (int i = 1; i <= N; i++)
		d_2[i] = inf;
	d_2[X] = 0;
	memset(done, 0, sizeof(done));
	Q.push(pii(0, X));
	while (!Q.empty())
	{
		pii x = Q.top();
		Q.pop();
		int u = x.second;		//u为当前结点的编号
		if (done[u])
			continue;
		done[u] = true;
		for (int i = 0; i < G_2[u].size(); i++)
		{
			Edge& e = edges_2[G_2[u][i]];
			if (d_2[e.to]>d_2[u] + e.dist)
			{
				d_2[e.to] = d_2[u] + e.dist;
				Q.push(pii(d_2[e.to], e.to));
			}
		}
	}
}


int main(void)
{
	scanf("%d %d %d", &N, &M, &X);
	for (int i = 0; i < M; i++)
	{
		int a, b, c;
		scanf("%d %d %d", &a, &b, &c);
		AddEdge_1(a, b, c);
		AddEdge_2(b, a, c);
	}

	dijkstra_1();
	dijkstra_2();

	for (int i = 1; i <= N; i++)
	{
		ans = max(ans, d_1[i] + d_2[i]);
	}

	printf("%d\n", ans);

	
	return 0;
}




农场主FJ有F个农场(F组数据),
一个农场有N块地(结点),编号1~N,
地与地之间有M条双向正权边,W条单向负权边(虫洞),
FJ想从农场的某点出发,经过一些结点后回到原点时,时间早于出发的时刻,
问:FJ能否在该农场实现这个愿望?
(1 ≤ N ≤ 500)    (1 ≤ M ≤ 2500)    (1 ≤ W ≤ 200)
要使结束的时间早于开始的时间,即为图中含有负圈,即检测给定图中是否有负圈。

Bellman-Ford模板题,
要注意输入正负边时的细节,以及总边数的处理,防止边数组开小了,另外注意一下重边的情况

AC-Code (C++)

Time: 125 ms  Memory: 764 kb

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#include<stack>
#include<string>
#include<vector>
#include<functional>
using namespace std;


const int MAXN = 505;
const int MAXM = 5500;				

const int INF = 1000000000;
int F, N, M, W;		//样例数,结点数,正边数(双向),负边数(单向)
int d[MAXM];		//到起点距离
int u[MAXM];		//起点
int v[MAXM];		//终点
int w[MAXM];		//权值
bool ans = false;


void bellman_ford(void)
{
	for (int k = 0; k <= N - 1; k++)
	{
		if (k == N - 1)
		{
			ans = true;
			break;
		}
		bool temp = false;
		for (int i = 1; i <= M * 2 + W; i++)
		{
			int x = u[i], y = v[i];
			if (d[x] < INF)
			{
				int dy = d[y];
				d[y] = min(d[y], d[x] + w[i]);
				if (d[y]!=dy)
					temp = true;
			}
		}
		if (!temp)
			break;
	}
	return;
}



int main(void)
{
	scanf("%d", &F);

	while (F--)
	{
		scanf("%d %d %d", &N, &M, &W);

		for (int i = 1; i <= M * 2 + W; i++)
		{
			w[i] = INF;
		}
		for (int i = 1; i <= N; i++)
		{
			d[i] = INF;
		}
		d[1] = 0;
		ans = false;


		for (int i = 1; i <= M; i++)
		{
			int a, b, c;
			scanf("%d %d %d", &a, &b, &c);
			int j = 2 * i - 1;
			u[j] = a;
			v[j] = b;
			w[j] = min(w[j], c);		//解决重边
			j++;
			u[j] = b;
			v[j] = a;
			w[j] = min(w[j], c);
		}
		for (int i = M * 2 + 1; i <= 2 * M + W; i++)
		{
			int a, b, c;
			scanf("%d %d %d", &a, &b, &c);
			u[i] = a;
			v[i] = b;
			w[i] = min(w[i], -1*c);
		}


		bellman_ford();


		if (ans)
			printf("YES\n");
		else
			printf("NO\n");
	}

	return 0;
}




有1~N一共N个结点,每个结点都有一头奶牛,

每只奶牛都打算到结点X(1<=X<=N)来参加派对,

并且在派对结束后回到原来的结点,

每只奶牛都选择最短的路程,

一共有M条单向的路,每条路通过的时间为Ti,(单向有权)

(1 ≤ N ≤ 1000)    (1 ≤ M ≤ 100,000)    (1 ≤ Ti ≤ 100)

问:来回的路程最长的奶牛经过的总路程为多少?

单源最短路(SSSP)问题的变种,“回家”即为从X到各点的最短路,“前往派对”即为将所有道路取反后,从X到各个点的最短路
比较稀疏的图,用Dijkstra模板即可

AC-Code (C++)

Time: 47 ms  Memory: 1060 kb




















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值
>