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

本文详细介绍了2016-2017 ACM-ICPC Northwestern European Regional Programming Contest (NWERC 2016)中的Problem I Iron and Coal。该问题涉及在棋盘游戏中找到从起点出发,通过最少步骤获取1号资源和2号资源的策略。解决方案包括使用SPFA算法计算起点到所有点的最短路径,然后通过反向建图和BFS找出到达最近1号资源和2号资源的最短距离。
摘要由CSDN通过智能技术生成

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++)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值