2016 Europe - Northwestern I - Iron and Coal UVALive - 7767(最短路)

There are many excellent strategy board games, and yourfavourite among them is called “Steel Age”. It o ers manydi erent paths to victory but you prefer the blood-and- re-strategy: build as many soldiers as possible and club youropposition into submission. To be able to build soldiers youneed two resources: iron ore and coal.

The board consists of di erent cells numbered from 1 to nwhich can contain resources. The rules for moving from onecell to another are rather complicated: if you can move fromcell A to cell B, it does not always mean that you can alsomove from B to A. For example, if two cells are connectedby a river, then you may be able to move downstream, butnot upstream, so long as you didn’t invent a steam engine;however, it still could be possible to reach the upstream cellby 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. Atevery move you are allowed to move an arbitrary number of settlers from a cell to one of its accessibleneighbours. By moving your settlers into a cell for the rst time, you “claim” it. Every claimed cellwill bind one settler, which has to stay in this cell until the end of the game. However, there is no needto leave a settler in your initial cell because it is where your palace is located and thus the cell staysclaimed for all time.

Your goal is to claim at least one cell containing the resource “iron ore” and at least one cell withresource “coal” in order to be able to build soldiers. What is the minimal number of settlers you needto reach this goal?

Input

The input le contains several test cases, each of them as described below.The input consists of:

  • One line with three integers n (2 n 105), the number of cells on the playing eld, m(1 m < n), the number of cells containing iron ore, and k (1 k < n), the number of cellscontaining coal.

  • One line with m distinct integers o1,...,om (1 oi n for all 1 i m), where o1,...,om arethe 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 theIDs of cells with coal.

  • n lines describing the topology of the board. The j-th line of this block speci es the accessibleneighbours of the j-th cell and consists of the following integers:

    One integer 0 a 10, the number of cells accessible from cell j.adistinctintegersb1,...,ba (1bi n,bi ̸=jforall1ia),theIDsofthecells

    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.

    Output

    For each test case, write on a line by itself, following the description below
    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

    3 1 1

    2
    3

    1 2

    2 3 1

    1 1

    3 1 1

    2

    3

    1 2

    1 1

    2 1 2

    Sample Output

    2

    impossible 

    一个有向图,有一个队伍从1点出发找到碳跟铁,问走过的最短路是多少。


    可以枚举所有点,求出点到这三个点的最短距离。

    从1点的正常跑单源最短路就好了

    因为碳跟铁是要求,各个点到该点的最短路,所以建立反向变求最短路

    跑三遍最短路,然后枚举既可以了

    #include <iostream>
    #include <algorithm>
    #include <stdio.h>
    #include <string.h>
    #include <queue>
    #include <vector>
    #include <utility>
    using namespace std;
    const int maxn = 200050;
    const long long INF = 0x3f3f3f3f;
    int n, m, k;
    int visited[maxn];
    int head[maxn], total;
    int dis[maxn][3];
    vector<int> state[3];
    
    vector<int> edge1[maxn], edge2[maxn];
    
    void init() {
        for (int i = 0; i < 3; ++i) {
            state[i].clear();
        }
        for (int i = 0; i <= n; ++i) {
            edge1[i].clear();
            edge2[i].clear();
        }
        state[0] = {1};
        memset(head, -1, sizeof(head));
        total = 0;
        memset(dis, INF, sizeof(dis));
    }
    template <int N>
    void bfs(int st, const vector<int>(&edge)[N]) {
        memset(visited, 0, sizeof(visited));
        queue<int> que;
        for (int i = 0; i < state[st].size(); ++i) {
            int u = state[st][i];
            visited[u] = 1;
            dis[u][st] = 0;
            que.push(u);
        }
        
        while (!que.empty()) {
            int u = que.front();
            que.pop();
            for (int i = 0; i < edge[u].size(); ++i) {
                int v = edge[u][i];
                if (dis[v][st] > dis[u][st] + 1) {
                    dis[v][st] = dis[u][st] + 1;
                    if (!visited[v]) {
                        visited[v] = 1;
                        que.push(v);
                    }
                }
            }
            visited[u] = 0;
        }
    }
    
    int main() {
            //freopen("in.txt", "r", stdin);
        ios::sync_with_stdio(false);
        while (cin >> n >> m >> k) {
            init();
            for (int i = 0; i < m; ++i) {
                int a;
                cin >> a;
                state[1].push_back(a);
            }
            for (int i = 0; i < k; ++i) {
                int a;
                cin >> a;
                state[2].push_back(a);
            }
            
            for (int i = 1; i <= n; ++i) {
                int s;
                cin >> s;
                for (int j = 0; j < s; ++j) {
                    int v;
                    cin >> v;
                    edge1[i].push_back(v);
                    edge2[v].push_back(i);
                }
            }
            bfs(0, edge1);
            bfs(1, edge2);
            bfs(2, edge2);
            long long res = INF;
            for (int i = 1; i <= n; ++i) {
                    //cout << dis[i][0] << " " << dis[i][1] << " " << dis[i][2] << endl;
                res = min(res, static_cast<long long>(dis[i][0]) + dis[i][1] + dis[i][2]);
            }
            if (res < INF)
                cout << res << endl;
            else
                cout << "impossible" << endl;
        }
    }


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值