Part0:前言
奆佬们怎么都说这题是两只手,我英文还是太菜了,就按红蓝两球来讲吧。
Part1:思路
显然,对于每局游戏,可将蓝球移动化为红球在反图上移动,需经过的边不变。于是我们就可以自然地想到使用分层图。
不同边的含义如下:
-
对于边 ( u , v , w ) (u,v,w) (u,v,w),表示正图的边。
-
对于边 ( v + n , u + n , w ) (v+n,u+n,w) (v+n,u+n,w),表示反图的边。
-
对于边 ( i , i + n , 0 ) (i,i+n,0) (i,i+n,0),表示从 i i i 开始走反图。
最终的输出即为 1 → i + n 1 \to i+n 1→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;
}