NWERC 2016
Problem I Iron and Coal Coal.
Photo by US Federal Government
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. The board consists of different cells numbered from 1 to n which can contain resources. The rules for moving from one cell to another are rather complicated: if you can move from cell A to cell B, it does not always mean that you can also move from B to A. For example, if two cells are connected by a river, then you may be able to move downstream, but not upstream, so long as you didn’t invent a steam engine; however, it still could be possible to reach the upstream cell by using roads and taking a detour over other cells. At the beginning of the game you own only one such cell, where all your settlers are located. At every move you are allowed to move an arbitrary number of settlers from a cell to one of its accessible neighbours. By moving your settlers into a cell for the first time, you “claim” it. Every claimed cell will bind one settler, which has to stay in this cell until the end of the game. However, there is no need to leave a settler in your initial cell because it is where your palace is located and thus the cell stays claimed for all time. Your goal is to claim at least one cell containing the resource “iron ore” and at least one cell with resource “coal” in order to be able to build soldiers. What is the minimal number of settlers you need to reach this goal? Input The input consists of: • One line with three integers n (2 ≤ n ≤ 105 ), the number of cells on the playing field, m (1 ≤ m < n), the number of cells containing iron ore, and k (1 ≤ k < n), the number of cells containing coal. • One line with m distinct integers o1, . . . , om (1 ≤ oi ≤ n for all 1 ≤ i ≤ m), where o1, . . . , om are the IDs of cells with iron ore. • One line with k distinct integers c1, . . . , ck (1 ≤ ci ≤ n for all 1 ≤ i ≤ k), where c1, . . . , ck are the IDs of cells with coal. • n lines describing the topology of the board. The j-th line of this block specifies the accessible neighbours of the j-th cell and consists of the following integers: – One integer 0 ≤ a ≤ 10, the number of cells accessible from cell j. – a distinct integers b1, . . . , ba (1 ≤ bi ≤ n, bi 6= j for all 1 ≤ i ≤ a), the IDs of the cells accessible from cell j. It is guaranteed, that no cell contains both resources, iron ore and coal. At the beginning of the game you own only the cell with ID 1. NWERC 2016 Problem I: Iron and Coal 17 NWERC 2016 Output Output the minimum number of settlers needed to claim at least one cell with coal and at least one cell with iron ore. Output “impossible” if it is impossible to own both, coal and iron ore. Sample Input 1 Sample Output 1 3 1 1 2 3 1 2 2 3 1 1 1 2 Sample Input 2 Sample Output 2 3 1 1 2 3 1 2 1 1 2 1 2 impossible NWERC 2016 Problem I: Iron and Coal 18
题意:从1号点出发,求找一个铁一个碳的最短路程。
题解:三遍SPFA,先反向建边第一次找到每个点到最近碳点的最短路,第二次找到每个点到最近铁点最短路。再正向建边,找到每个点到1号点的最短路。最后遍历每个点的三个距离dis1,dis2,dis3,找出最小值。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<cmath>
#include<queue>
#include<map>
#include<algorithm>
#include<vector>
using namespace std;
const int MaxN = 2e6;
typedef long long LL;
typedef unsigned long long ULL;
int dis1[MaxN + 5],dis2[MaxN + 5],dis3[MaxN + 5],vis[MaxN + 5],pre[MaxN + 5],last[MaxN + 5],other[MaxN + 5],U[MaxN + 5],V[MaxN + 5],a[MaxN + 5],b[MaxN + 5];
queue<int>q;
int n,m,k,all,tot;
LL ans;
void Build(int y,int x){
pre[++all] = last[x];
last[x] = all;
other[all] = y;
}
void SPFA1(){
int now,ed,dr;
for(int i = 1;i <= m;i++){
vis[a[i]] = 1;
dis1[a[i]] = 0;
q.push(a[i]);
}
while(!q.empty()){
now = q.front();
ed = last[now];
while(ed != -1){
dr = other[ed];
if(dis1[now] + 1 < dis1[dr]){
dis1[dr] = dis1[now] + 1;
if(!vis[dr]){
vis[dr] = 1;
q.push(dr);
}
}
ed = pre[ed];
}
q.pop();
vis[now] = 0;
}
}
void SPFA2(){
int now,ed,dr;
for(int i = 1;i <= k;i++){
vis[b[i]] = 1;
dis2[b[i]] = 0;
q.push(b[i]);
}
while(!q.empty()){
now = q.front();
ed = last[now];
while(ed != -1){
dr = other[ed];
if(dis2[now] + 1 < dis2[dr]){
dis2[dr] = dis2[now] + 1;
if(!vis[dr]){
vis[dr] = 1;
q.push(dr);
}
}
ed = pre[ed];
}
q.pop();
vis[now] = 0;
}
}
void SPFA3(){
int now,ed,dr;
vis[1] = 1;
q.push(1);
dis3[1] = 0;
while(!q.empty()){
now = q.front();
ed = last[now];
while(ed != -1){
dr = other[ed];
if(dis3[now] + 1 < dis3[dr]){
dis3[dr] = dis3[now] + 1;
if(!vis[dr]){
vis[dr] = 1;
q.push(dr);
}
}
ed = pre[ed];
}
q.pop();
vis[now] = 0;
}
}
int main(){
ans = 2000000000LL;
tot = 0;
all = -1;
scanf("%d%d%d",&n,&m,&k);
for(int i = 1;i <= 1e6+5;i++)last[i] = -1;
for(int i =0;i <= n;i++){
dis1[i] = 2000000000LL;
dis2[i] = 2000000000LL;
dis3[i] = 2000000000LL;
}
for(int i = 1;i <= m;i++)scanf("%d",&a[i]);
for(int i = 1;i <= k;i++)scanf("%d",&b[i]);
int u ,v;
for(int i = 1;i <= n;i++){
scanf("%d",&u);
for(int j = 1;j <= u;j++){
scanf("%d",&v);
Build(i,v);
U[++tot] = v;
V[tot] = i;
}
}
SPFA1();
SPFA2();
for(int i = 0;i <= all;i++){
pre[i] = 0;
other[i] = 0;
}
for(int i = 1;i <= n;i++)last[i] = -1;
all = -1;
for(int i = 1;i <= tot ;i++)Build(U[i],V[i]);
SPFA3();
for(int i = 1;i <= n;i++){
ans = min(ans,((LL)dis1[i] + (LL)dis2[i] + (LL)dis3[i]));
}
if(ans == 2000000000LL)printf("impossible\n");
else printf("%d\n",(int)ans);
}