AtCoder ARC061Eすぬけ君の地下鉄旅行 / Snuke's Subway Trip 【拆点最短路 + 思维】 好题!

版权声明:本文为博主原创文章,喜欢就点个赞吧 https://blog.csdn.net/Anxdada/article/details/81903635

传送门
题意: 有一个n个点m条边的无向图, 边上有一个编号, 表示这条边归编号公司管理, 如果相邻的两条边的编号相同, 则代价为0. 否则代价加1, 其实为1, 问1到n的最低代价为多少.

思路: 这道题的思路真的是秒啊!!! 很明显我们要解决的问题就是如果让相同公司之间的花费为0, 所以我们进行拆点, 将u v c, 拆成u - uc, uc - vc, vc - v, 边权分别是1, 0, 1, 这样就可以让相邻的相同的公司的边之间的花费为0了. 比如:
这里写图片描述
将边拆掉后重建的图:
这里写图片描述

然后这样直接跑新图1-n的最短路然后/2就是答案. 理解的话就是在起点站上车需要以代价, 中间如果是相同公司则不需要花费代价, 下车有需要一个代价, 所以最后答案要/2.

更直接的样例就是:
3 2
1 2 1
2 3 1

新图为:

1 - (1, 1) - (2, 1) - 2
(2, 1) - (3, 1) - 3
所以就是通过1 -> (1, 1) -> (2, 1) -> (3, 1) - 3. 代价为2, /2 = 1就是答案
注意这样拆点后,边和点都会变得比较多. 范围要开大点. 然后建好跑最短路即可.
AC Code

const int maxn = 1e6+5;
int n, m;
struct node {
    int to, next, w;
    bool operator < (const node& a) const {
        return w > a.w;
    }
} e[maxn<<1];
int cnt, head[maxn];
void add(int u, int v, int w) {
    e[cnt] = node{v, head[u], w};
    head[u] = cnt++;
}
bool vis[maxn];
int dis[maxn];
void dij(int st, int ed) {
    priority_queue<node> q;
    Fill(dis,inf); Fill(vis,0);
    dis[st] = 0;
    q.push(node{st, 0, 0});
    while (!q.empty()) {
        node u = q.top();
        q.pop();
        if(vis[u.to]) continue;
        vis[u.to] = 1;

        for (int i = head[u.to]; ~i; i = e[i].next) {
            int to = e[i].to;
            if (dis[to] > dis[u.to] + e[i].w) {
                dis[to] = dis[u.to] + e[i].w;
                q.push(node{to, 0, dis[to]});
            }
        }
    }
    printf("%d\n", dis[ed] == inf?-1:dis[ed]/2);
}
map<int, int>mp[maxn];
void init() {
    cnt = 0; Fill(head, -1);
    for (int i = 1 ; i <= n ; i ++) {
        mp[i].clear();
    }
}
int getid(int x, int y) {
    if (!mp[x][y]) mp[x][y] = ++n;
    return mp[x][y];
}
void solve() {
    while(~scanf("%d%d", &n, &m)) {
        init(); int ed = n;
        for (int i = 1 ; i <= m ; i ++) {
            int u, v, c;
            scanf("%d%d%d", &u, &v, &c);
            int uc = getid(u, c);
            int vc = getid(v, c);
            add(uc, vc, 0); add(vc, uc, 0);
            add(u, uc, 1); add(uc, u, 1);
            add(v, vc, 1); add(vc, v, 1);
        }
        dij(1, ed);
    }
}

猜你喜欢

转载自blog.csdn.net/Anxdada/article/details/81903635