AtCoder ARC061E Snuke's Subway Trip 最短路

目录

  • Catalog
  • Solution:

(有任何问题欢迎留言或私聊 && 欢迎交流讨论哦

Catalog

Problem:传送门

?Portal

?原题目描述在最下面。

?\(n(1e5)\)个点, \(m(2e5)\)条边, 每条边有一个属性值。经过一条同一属性值的连续路径花费为1。问从1到n的最小花费。

Solution:

我的解法

?直接边最短路搞,然后t的飞起。仔细一想,这样写的话有\(1e5\)个点,边数更是多到飞起,拿命跑啊,不过代码我还是放下面。



正解:拆点

?把一条\(u->v\)属性为\(c\)的路径,拆成\(u->uc, uc->vc, vc->v\)三条路径,边权分别为\(1, 0, 1\)。

?然后跑最裸的最短路就行,答案除\(2\)输出。

why?

?为什么这样是对的呢?

?对于一个点连接的许多路径,从一条走向另一条,如果属性相同就不需要额外花费。这点怎么做到的呢?

?比如\(x->y,y->z\)属性均为\(c\):实际路径是\(x->yc->z\),经过了yc这个中间点,而且没有额外的花费。

?答案除\(2\)是因为出发和结束都算了一遍花费。

AC_Code:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <unordered_map>
#define fi first
#define se second
#define iis std::ios::sync_with_stdio(false)
using namespace std;
typedef long long LL;
typedef unsigned long long uLL;
typedef pair<int, int> pii;

const int INF = 0x3f3f3f3f;
const int MXN = 1e6 + 5;
const int MXT = 2e7 + 6;
const uLL base = 99959;

unordered_map<uLL, int> mp;
int n, m, tn;
int head[MXN], tot;
struct lp {
    int v, c, nex;
}cw[MXT];
int dis[MXT], vis[MXT], fa[MXN];
void add_edge(int u,int v,int w) {
    cw[++tot].v = v;cw[tot].c = w;cw[tot].nex = head[u];
    head[u] = tot;
    cw[++tot].v = u;cw[tot].c = w;cw[tot].nex = head[v];
    head[v] = tot;
}
void dij() {
    priority_queue<pii,vector<pii>,greater<pii> >Q;
    for(int i = 1; i <= n; ++i) dis[i] = INF, vis[i] = 0;
    dis[1] = 0;
    Q.push({dis[1], 1});
    while(!Q.empty()) {
        pii now = Q.top();Q.pop();
        int u = now.se;
        if(vis[u]) continue;
        vis[u] = 1;
        for(int i = head[u]; ~i; i = cw[i].nex) {
            int v = cw[i].v;
            //if(vis[v]) continue;
            if(dis[v] > dis[u] + cw[i].c) {
                dis[v] = dis[u] + cw[i].c;
                Q.push({dis[v], v});
            }
        }
    }
    int ans = dis[tn];
    while(!Q.empty()) Q.pop();
    if(ans == INF) ans = -2;
    printf("%d\n", ans/2);
}
int Fi(int x) {
    return fa[x] == x? x: fa[x] = Fi(fa[x]);
}
int get(int x, int y) {
    uLL tmp = x;
    tmp = tmp * base * base + y * base + x ^ y;
    if(mp[tmp]) return mp[tmp];
    mp[tmp] = ++n;
    return n;
}
int main(int argc, char const *argv[]) {
    while(~scanf("%d%d", &n, &m)) {
        memset(head, -1, sizeof(head));
        tot = -1;
        mp.clear();
        tn = n;
        for(int i = 1; i <= n; ++i) fa[i] = i;
        for(int i = 0, u, v, c, pa, pb, uc, vc; i < m; ++i) {
            scanf("%d%d%d", &u, &v, &c);
            pa = Fi(u), pb = Fi(v);
            fa[pa] = pb;
            uc = get(u, c); vc = get(v, c);
            add_edge(u,uc,1);add_edge(uc,vc,0);add_edge(vc,v,1);
            add_edge(v,vc,1);add_edge(vc,uc,0);add_edge(uc,u,1);
        }
        if(Fi(tn) != Fi(1)){
            printf("-1\n");
            continue;
        }
        dij();
    }
    return 0;
}

TLE_code

#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <unordered_map>
#define fi first
#define se second
#define iis std::ios::sync_with_stdio(false)
using namespace std;
typedef long long LL;
typedef unsigned long long uLL;
typedef pair<int, int> pii;

const int INF = 0x3f3f3f3f;
const int MXN = 1e5 + 5;
const int MXT = 4e5 + 6;

int n, m;
int head[MXN], tot;
struct lp {
    int v, c, nex;
}cw[MXT];
vector<pii> mp[MXN];
int dis[MXT], vis[MXT], fa[MXN];
void add_edge(int u,int v,int w) {
    cw[++tot].v = v;cw[tot].c = w;cw[tot].nex = head[u];
    head[u] = tot;
    cw[++tot].v = u;cw[tot].c = w;cw[tot].nex = head[v];
    head[v] = tot;
}
void dij() {
    priority_queue<pii,vector<pii>,greater<pii> >Q;
    memset(dis, 0x3f, sizeof(dis));
    memset(vis, 0, sizeof(vis));
    for(int i = head[1]; ~i; i = cw[i].nex) {
        dis[i] = 1;
        Q.push({dis[i], i});
    }
    int ans = INF;
    while(!Q.empty()) {
        pii now = Q.top();Q.pop();
        if(vis[now.se]) continue;
        vis[now.se] = 1;
        int u = now.se, a = cw[u].v;
        if(a == n) {
            ans = min(ans, dis[u]);
            break;
        }
        for(int i = head[a]; ~i; i = cw[i].nex) {
            if(vis[i]) continue;
            if(dis[i]>dis[u]+(cw[i].c!=cw[u].c)) {
                dis[i] = dis[u]+(cw[i].c!=cw[u].c);
                Q.push({dis[i], i});
            }
        }
    }
    while(!Q.empty()) Q.pop();
    if(ans == INF) ans = -1;
    printf("%d\n", ans);
}
int Fi(int x) {
    return fa[x] == x? x: fa[x] = Fi(fa[x]);
}
int main(int argc, char const *argv[]) {
    while(~scanf("%d%d", &n, &m)) {
        memset(head, -1, sizeof(head));
        tot = -1;
        for(int i = 1; i <= n; ++i) fa[i] = i;
        for(int i = 0, u, v, c, pa, pb; i < m; ++i) {
            scanf("%d%d%d", &u, &v, &c);
            add_edge(u, v, c);
            pa = Fi(u), pb = Fi(v);
            fa[pa] = pb;
        }
        if(Fi(n) != Fi(1)){
            printf("-1\n");
            continue;
        }
        dij();
    }
    return 0;
}

Problem Description:

AtCoder ARC061E Snuke's Subway Trip 最短路

原文地址:https://www.cnblogs.com/Cwolf9/p/9749976.html

时间: 2024-10-17 08:26:46

AtCoder ARC061E Snuke's Subway Trip 最短路的相关文章

Atcoder Snuke&#39;s Subway Trip 重构图

题目链接 这题主要是重构图的方法很难思考. 方法一:考虑在每个公司意义下的联通块,每个联通块对应一个虚拟节点,联通块内的节点到联通块对应的虚拟节点有一条边,构建出一个二分图,跑一遍BFS,将经过的边数除以2.这里有两种实现,                             细节都注释在了程序里 1 #include<bits/stdc++.h> 2 using namespace std; 3 vector<pair<int,int> > nei[1000005

[ARC061E]すぬけ君の地下鉄旅行 / Snuke&#39;s Subway Trip

题目大意:Snuke的城镇有地铁行驶,地铁线路图包括$N$个站点和$M$个地铁线.站点被从$1$到$N$的整数所标记,每条线路被一个公司所拥有,并且每个公司用彼此不同的整数来表示. 第$i$条线路($1\le i \le M$)是直接连接$p_i$与$q_i$的双向铁路,中间不存在其他站点,且这条铁路由$c_i$公司所拥有. 如果乘客只乘坐同一公司的铁路,他只需要花费一元,但如果更换其他公司的铁路需要再花一元.当然,如果你要再换回原来的公司,你还是要花一元. Snuke在1号站的位置出发,他想通

【例题收藏】◇例题&#183;I◇ Snuke&#39;s Subway Trip

◇例题·I◇ Snuke's Subway Trip 题目来源:Atcoder Regular 061 E题(beta版) +传送门+ 一.解析 (1)最短路实现 由于在同一家公司的铁路上移动是不花费的,只有在换乘时会花费1日元.我们可以视换乘的花费为点权--当换乘到不同公司时花费1,同一家公司时花费0. 对于这种点权因情况而变化的题,最常见的做法便是拆点.设节点 u 相连的铁路由 c1,c2,...,cp p个公司修建,则将节点u拆分为节点 uc1~ucp,点uci表示到达点u的铁路是由公司c

POJ 2502 SUBWAY(最短路)

POJ 2502 SUBWAY 题目链接:http://poj.org/problem?id=2502 题目大意:求从a点到b点所需要的最短时间. 题目思路:用最短路来求,把各个点之间的时间看作所需要的路程.然后用 dij求最短路就可以了,感觉输入有点坑,还有在每条地铁线上,只有相同地铁线上的 点可以互相到达. #include<stdio.h> #include<algorithm> #include<math.h> using namespace std; cons

POJ 2502 Subway (Dijkstra 最短路+建图)

Subway Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 6689   Accepted: 2176 Description You have just moved from a quiet Waterloo neighbourhood to a big, noisy city. Instead of getting to ride your bike to school every day, you now get

csp退役前的做题计划1(真)

csp退役前的做题计划1(真) 因为我太菜了,所以在第一次月考就会退役,还是记录一下每天做了什么题目吧. 任务计划 [ ] Z算法(Z Algorithm) 9.28 [x] ARC061C たくさんの数式 / Many Formulas [x] ARC061D すぬけ君の塗り絵 / Snuke's Coloring [x] ARC061E すぬけ君の地下鉄旅行 / Snuke's Subway Trip [x] ARC061F 3人でカードゲーム / Card Game for Three [

すぬけ君の塗り絵 / Snuke&#39;s Coloring AtCoder - 2068 (思维,排序,贡献)

Problem Statement We have a grid with H rows and W columns. At first, all cells were painted white. Snuke painted N of these cells. The i-th ( 1≤i≤N ) cell he painted is the cell at the ai-th row and bi-th column. Compute the following: For each inte

BZOJ 1395 [Baltic2005]Trip(最短路+DP)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1354 [题目大意] 给出一些车的班次,包括起点,终点,到达起点时间区间, 到达终点时间区间,想要T时刻到达n号点,问最坏情况下的最短等待时间 [题解] 最坏情况就是每次从b时刻才出发,c时刻到达, 那么就相当于地点从x到y,时间从a到d,代价为c-b, 我们求出符合要求的最大代价,然后用最终时间T去减即可 如果没有a和d这个限制,可以直接求最长路即可, 现在考虑如何消除a和d这个时间

Subway POJ - 2502 最短路

题意:给出地铁线  起点和 终点  坐地铁速度为v2  走路为v1 求起点到终点的最短距离  (答案需要四舍五入这里坑了好久) 拿给出的地铁站点 和起点终点建边即可  然后跑个迪杰斯特拉 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 using namespace std; 6 const double v1=10000.0/60; 7 cons