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++)