CF1725M Moving Both Hands 绿 题解
Part0:前言
奆佬们怎么都说这题是两只手,我英文还是太菜了,就按红蓝两球来讲吧。
Part1:思路
显然,对于每局游戏,可将蓝球移动化为红球在反图上移动,需经过的边不变。于是我们就可以自然地想到使用分层图。
不同边的含义如下:
-
对于边 \((u,v,w)\),表示正图的边。
-
对于边 \((v+n,u+n,w)\),表示反图的边。
-
对于边 \((i,i+n,0)\),表示从 \(i\) 开始走反图。
最终的输出即为 \(1 \to i+n\) 的最短路程。
Part2:代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
int n,m,k,tot,hd[2000010],nx[2000010],to[2000010],vl[2000010],dis[2000010];
bool vis[2000010];
void add (int u,int v,int w) {
nx[++tot]=hd[u];
to[tot]=v;
vl[tot]=w;
hd[u]=tot;
}
signed main () {
cin>> n>> m;
for (int i=1,u,v,w;i<=m;i++) {
cin>> u>> v>> w;
add (u,v,w);
add (v+n,u+n,w);
}
for (int i=1;i<=n;i++)
add (i,i+n,0);
priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > heap;
memset (dis,0x3f,sizeof dis);
heap.push ({0,1});
dis[1]=0;
while (heap.size ()) {
int u=heap.top ().second;
heap.pop ();
if (vis[u]) continue;
vis[u]=1;
for (int i=hd[u];i;i=nx[i]) {
int v=to[i],w=vl[i];
if (dis[v]>dis[u]+w) {
dis[v]=dis[u]+w;
heap.push ({dis[v],v});
}
}
}
for (int i=n+2;i<=n*2;i++)
cout<< (dis[i]==0x3f3f3f3f3f3f3f3f? -1: dis[i])<< " ";
return 0;
}
#include <bits/stdc++.h>
using namespace std;
#define int long long
int n,m,k,tot,hd[2000010],nx[2000010],to[2000010],vl[2000010],dis[2000010];
bool vis[2000010];
void add (int u,int v,int w) {
nx[++tot]=hd[u];
to[tot]=v;
vl[tot]=w;
hd[u]=tot;
}
signed main () {
cin>> n>> m;
for (int i=1,u,v,w;i<=m;i++) {
cin>> u>> v>> w;
add (u,v,w);
add (v+n,u+n,w);
}
for (int i=1;i<=n;i++)
add (i,i+n,0);
priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > heap;
memset (dis,0x3f,sizeof dis);
heap.push ({0,1});
dis[1]=0;
while (heap.size ()) {
int u=heap.top ().second;
heap.pop ();
if (vis[u]) continue;
vis[u]=1;
for (int i=hd[u];i;i=nx[i]) {
int v=to[i],w=vl[i];
if (dis[v]>dis[u]+w) {
dis[v]=dis[u]+w;
heap.push ({dis[v],v});
}
}
}
for (int i=n+2;i<=n*2;i++)
cout<< (dis[i]==0x3f3f3f3f3f3f3f3f? -1: dis[i])<< " ";
return 0;
}

浙公网安备 33010602011771号