#Dijkstra,博弈论#ABC261 Ex - Game on Graph

题目传送门


分析

相当于是从任意出点出发到起点,设 \(dis[0/1][x]\) 表示先手/后手从 \(x\) 出发获得的最小/最大得分,

\(dis[0][x]=\min\{dis[1][y]+w\},dis[1][x]=\max\{dis[0][y]+w\}\)

而先手的最小得分可以直接用最短路实现,而 \(dis[1][x]\) 需要它的所有后继 \(dis[0][y]\)

因此记录出度直到它的后继全部计算完才将其丢入优先队列。


代码

#include <cstdio>
#include <cctype>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
const int N=200011;
struct rec{
	int z,x; long long d;
	bool operator <(const rec &t)const{
		return d>t.d;
	}
};
struct node{int y,w,next;}e[N];
priority_queue<rec>q;
int n,m,S,deg[N],as[N]; long long dis[2][N];
int iut(){
	int ans=0; char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=ans*10+c-48,c=getchar();
	return ans;
}
int main(){
	n=iut(),m=iut(),S=iut();
	for (int i=1;i<=m;++i){
		int x=iut(),y=iut(),w=iut();
		e[i]=(node){x,w,as[y]},as[y]=i,++deg[x];
	}
	memset(dis[0],0x3f,sizeof(dis[0]));
	memset(dis[1],0xcf,sizeof(dis[1]));
	for (int i=1;i<=n;++i)
	if (!deg[i]){
		dis[0][i]=dis[1][i]=0;
		q.push((rec){0,i,0});
		q.push((rec){1,i,0});
	}
	while (!q.empty()){
		rec t=q.top(); q.pop();
		if (dis[t.z][t.x]!=t.d) continue;
		if (!t.z){
			for (int i=as[t.x];i;i=e[i].next){
				dis[1][e[i].y]=max(dis[1][e[i].y],dis[0][t.x]+e[i].w);
				if (--deg[e[i].y]==0) q.push((rec){1,e[i].y,dis[1][e[i].y]});
			}
		}else{
			for (int i=as[t.x];i;i=e[i].next)
			if (dis[0][e[i].y]>dis[1][t.x]+e[i].w){
				dis[0][e[i].y]=dis[1][t.x]+e[i].w;
				q.push((rec){0,e[i].y,dis[0][e[i].y]});
			}
		}
	}
	if (dis[0][S]<0x3f3f3f3f3f3f3f3f) printf("%lld\n",dis[0][S]);
	    else printf("INFINITY\n");
	return 0;
}
posted @ 2025-06-30 15:16  lemondinosaur  阅读(11)  评论(0)    收藏  举报