COMPFEST 14 - Preliminary Online Mirror (Unrated, ICPC Rules, Teams Preferred) M. Moving Both Hands

探讨一个关于图论的经典单源最短路径问题,玩家需要在特定的有向图中移动两手到同一顶点结束游戏,寻找最优解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

 翻译:

Pak Chanek正在玩他最喜欢的一种棋盘游戏。在游戏中,有一个有向图,顶点为𝑁,边为𝑀。在图中,边𝑖连接两个不同的顶点𝑈𝑖和𝑉𝑖,长度为𝑊𝑖。通过使用𝑖-th边缘,可以从𝑈𝑖移动到𝑉𝑖,但不能从𝑉𝑖移动到𝑈𝑖。

要玩这个游戏,首先Pak Chanek必须把他的双手放在两个不同的顶点上。在一个动作中,他可以移动他的一只手到另一个顶点使用边。将一只手从顶点𝑈𝑖移动到顶点𝑉𝑖,Pak Chanek需要𝑊𝑖秒的时间。注意Pak Chanek一次只能移动一只手。当Pak Chanek的双手都在同一顶点时,游戏结束。

Pak Chanek有几个问题。对于每个𝑝满足2≤𝑝≤𝑁,你需要找出Pak Chanek结束游戏所需的最小时间(以秒为单位),如果最初Pak Chanek的左手和右手放在顶点1和顶点𝑝上,或者报告如果不可能的话。

输入
第一行包含两个整数𝑁和𝑀(2≤𝑁≤105,0≤𝑀≤2⋅105)——图中顶点和边的数量。

下𝑀行包含三个整数的𝑖-th𝑈𝑖,𝑉𝑖,和𝑊𝑖(1≤𝑈𝑖,𝑉𝑖≤𝑁,𝑈𝑖≠𝑉𝑖,1≤𝑊𝑖≤109)——一个有向边,连接两个顶点𝑈𝑖和𝑉𝑖长度的𝑊𝑖。没有一对不同的边𝑖和𝑗使得𝑈𝑖=𝑈𝑗和𝑉𝑖=𝑉𝑗。

输出
输出包含𝑁−1个整数的行。𝑗-th整数表示Pak Chanek结束游戏所需的最小时间(以秒为单位),如果最初Pak Chanek的左手和右手被放置在顶点1和顶点𝑗+1上,如果不可能,则放置在顶点−1上。

例子
inputCopy
5 7
1 2 2
2 4 1
4 1 4
2 5 3
5 4 1
5 2 4
2 1 1
outputCopy
1 -1 3 4
请注意
如果最初Pak Chanek的左手在顶点1上,他的右手在顶点5上,Pak Chanek可以做以下动作:

1秒内移动他的右手到顶点4。
2秒内将他的左手移到顶点2。
1秒内移动他的左手到顶点4。


总共需要1+2+1=4秒。可以证明没有其他方法比它更快。

思路:一个起点到很多点的的最短距离,单源最短路,用dijkstra建反向边,然后可以求解。感觉是一道很经典的最短路的图论题目。

代码:

#include <iostream>
#include <algorithm>
#include <string.h>
#include <string>
#include <math.h>
#include <stdio.h>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<tuple>
#include<numeric>
using namespace::std;
typedef long long  ll;
inline __int128 read(){
    __int128 x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9'){
        if(ch == '-')
            f = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9'){
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return x * f;
}
inline void print(__int128 x){
    if(x < 0){
        putchar('-');
        x = -x;
    }
    if(x > 9)
        print(x / 10);
    putchar(x % 10 + '0');
}
int n,m;
ll wa,ac;
vector<pair<ll, ll>>q[100005];
vector<pair<ll, ll>>w[100005];
ll a,b,c;
ll dis[100005][3];
int bj[100005];
void dijkstra(ll x){
    for (int i = 0; i<=n; i++) {
        dis[i][0]=dis[i][1]=1e18;
        bj[i]=0;
    }
    dis[x][1]=dis[x][0]=0;
    priority_queue< pair<ll, ll> ,vector<pair<ll, ll>>,greater<pair<ll, ll>>>ds;
    ds.push({0,1});
    ds.push({0,-1});
    while (!ds.empty()) {
        pair<ll,ll> kl=ds.top();ds.pop();
        ac=kl.first;wa=abs(kl.second);
        if (kl.second>0&&!(bj[wa]&1)) {
            bj[wa]|=1;
            for (auto k:q[wa]) {
                if (dis[k.first][0]>ac+k.second) {
                    dis[k.first][0]=ac+k.second;
                    ds.push({dis[k.first][0],k.first});
                }
            }
            for(auto k:w[wa]){
                if (dis[k.first][1]>ac+k.second) {
                    dis[k.first][1]=ac+k.second;
                    ds.push({dis[k.first][1],-k.first});
                }
            }
        }
        if (kl.second<0&&!(bj[wa]&2)) {
            bj[wa]|=2;
            for(auto k:w[wa]){
                if (dis[k.first][1]>ac+k.second) {
                    dis[k.first][1]=ac+k.second;
                    ds.push({dis[k.first][1],-k.first});
                }
            }
        }
    }
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(); cout.tie();
    cin>>n>>m;
    for(int i =1;i<=m;i++){
        cin>>a>>b>>c;
        q[a].push_back({b,c});
        w[b].push_back({a,c});
    }
    dijkstra(1);
    for (int i =2; i<=n; i++) {
        if (dis[i][0]==dis[i][1]&&dis[i][0]==1e18) {
            printf("-1 ");continue;
        }
        printf("%lld ",min(dis[i][1],dis[i][0]));
    }printf("\n");
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值