CF1725M Moving Both Hands 绿 题解

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 1i+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;
}

Part3:后记

分层图板题,如果想要练手的话,还可以做一做 P4568P4822 等题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值