#BFS# 2016-2017 ACM-ICPC Northwestern European Regional Programming Contest (NWERC 2016)

版权声明:本文为博主原创文章,转载清注明出处 https://blog.csdn.net/Jasmineaha/article/details/83218704

2016-2017 ACM-ICPC Northwestern European Regional Programming Contest (NWERC 2016)

Problem I Iron and Coal

题目链接http://codeforces.com/gym/101170/attachments

There are many excellent strategy board games, and your favourite among them is called “Steel Age”. It offers many different paths to victory but you prefer the blood-and-fire-strategy: build as many soldiers as possible and club your opposition into submission. To be able to build soldiers you need two resources: iron ore and coal.

Description

在 n 个点里,每个点只有没有资源、有 1 号资源和有 2 号资源这三种状态,从 1 这个点出发,寻找一个 1 号资源和一个 2 号资源的最短路,需要注意的是对于走过的重复路径只计算一次

Solution

值得注意的是:重复路径只计算一次,这就意味着有两种路径,第一种是在不会出现路径重复的情况下拿到两种资源,第二种是从起点走到一个岔路口 p,然后分别从p走到一个 1 号资源和一个 2 号资源(因为重复路径只计算一次)。

那么问题就转化为了在 n 个中寻找一个点 p,使得点 p 可以通到起点、一个 1 号资源和一个 2 号资源,那么答案就是这三个距离之和!
首先利用单源最短路径算法 SPFA 计算出起点到所有点的最短距离为 cost[i],然后反向建图,利用 BFS 找出每个点到最近的 1 号资源和 2 号资源的距离(全部资源同时当起点开始bfs),然后遍历所有点,把这 3 个距离取和求最小值。

也可以直接三次 BFS,代码量少又直观一些:

  • 第一遍BFS:从1号点BFS一遍整个正向边的图,记录数组 dist[0][i] 为每个点距离1号点的距离。
  • 第二遍BFS:从每个铁矿BFS一遍整个反向边的图,记录数组dist[1][i]为每个点距离每个铁矿的最近距离。
  • 第三遍BFS:从每个煤BFS一遍整个反向边的图,和第二遍类似。
    对于每个点,三个 dist 数组求和就是从一号点到最近的 1 号资源和最近的 2 号资源距离和。

Code

#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <cstdlib>
using namespace std;
const int MaxN = 1e5 + 5;
const int INF = 0x3f3f3f3f;

struct node {
	int x, t;
}S;

vector<int> G[MaxN], re_G[MaxN];
vector<int> loc[3];
int col[MaxN], iro[MaxN];
int vis[MaxN], cost[MaxN];
int val[MaxN][3];
int n, m, k;

void SPFA(){
	S.x = 1, S.t = 0;
	queue<node> que;
	que.push(S);
	vis[1] = true;
	memset(cost, INF, sizeof(cost));
	cost[1] = 0;
	while(!que.empty()){
		node now = que.front(), nxt;
		que.pop();
		for(int i = 0; i < G[now.x].size(); i++) {
			int v = G[now.x][i];
			nxt.x = v; nxt.t = now.t + 1;
			if(nxt.t < cost[nxt.x]) {
				cost[nxt.x] = nxt.t;
				if(!vis[nxt.x]) {
					que.push(nxt);
					vis[nxt.x] = true;
				}
			}
		}
		vis[now.x] = false;
	}
}

void BFS() 
{
	memset(val, 0x3f3f3f3f, sizeof(val));
	for(int i = 1; i <= n; i++) {
		if(col[i]) loc[1].push_back(i), val[i][1] = 0; //1号资源的所有位置
		if(iro[i]) loc[2].push_back(i), val[i][2] = 0; //2号资源的所有位置
	}
	for(int i = 1; i <= 2; i++) {
		for(int j = 0; j < loc[i].size(); j++) {
			int now = loc[i][j];
			for(int k = 0; k < re_G[now].size(); k++) {
				int u = re_G[now][k];
				int c = val[now][i] + 1;
				if(val[u][i] == INF) val[u][i] = c, loc[i].push_back(u);
			}
		}
	}
}

int main() 
{
	scanf("%d %d %d", &n, &m, &k);
	for(int i = 1; i <= m; i++) {
		int x; scanf("%d", &x);
		col[x] = 1;
	}
	for(int i = 1; i <= k; i++) {
		int x; scanf("%d", &x);
		iro[x] = 1;
	}
	for(int i = 1; i <= n; i++) {
		int t; scanf("%d", &t);
		while(t--) {
			int x; scanf("%d", &x);
			G[i].push_back(x);
			re_G[x].push_back(i);
		}
	}
	SPFA();
	BFS();
	int ans = INF;
	for(int i = 1; i <= n; i++) 
		if(cost[i] != INF && val[i][1] != INF && val[i][2] != INF)
			ans = min(ans, cost[i] + val[i][1] + val[i][2]);
	if(ans == INF) printf("impossible\n");
	else printf("%d\n", ans);
	return 0;
}

对于三次 BFS 的代码:

#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <cstdlib>
using namespace std;
const int MaxN = 2e5 + 5;
const int INF = 100000000;
//这里赋值为0x3f3f3f3f就会玄学wa22,不知道为什么....希望有大佬指点

vector<int> G[MaxN], re_G[MaxN];
int s[] = {0, 1}, col[MaxN], iro[MaxN];
int dist[3][MaxN];

void BFS(int id, int *src, int num, vector<int> *vec) 
{
	queue<int> que;
	for(int i = 0; i < MaxN; i++) dist[id][i] = INF;
    for(int i = 1; i <= num; i++) {
        dist[id][src[i]] = 0;
        que.push(src[i]);
    }
    while(!que.empty()) {
		int now = que.front(); que.pop();
        for(int i = 0; i < vec[now].size(); i++) {
            int nxt = vec[now][i];
            if(dist[id][nxt] == INF) {
                dist[id][nxt] = dist[id][now] + 1;
                que.push(nxt);
            }
		}
	}
}

int main() 
{
	int n, m, k;
	scanf("%d %d %d", &n, &m, &k);
	for(int i = 1; i <= m; i++) scanf("%d", &col[i]);
	for(int i = 1; i <= k; i++) scanf("%d", &iro[i]);
	for(int i = 1; i <= n; i++) {
		int t; scanf("%d", &t);
		while(t--) {
			int x; scanf("%d", &x);
			G[i].push_back(x);
			re_G[x].push_back(i);
		}
	}
	BFS(0, s, 1, G);
	BFS(1, col, m, re_G);
	BFS(2, iro, k, re_G);
	int ans = INF;
	for(int i = 1; i <= n; i++) 
		ans = min(ans, dist[0][i] + dist[1][i] + dist[2][i]);
	if(ans == INF) printf("impossible\n");
	else printf("%d\n", ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Jasmineaha/article/details/83218704