[dp] [dijsktra] [ABC261Ex] Game on Graph

posted on 2024-04-25 02:52:41 | under | source

\(f_{u,0/1}\) 表示节点 \(u\) 出发且 \(\rm Takahashi\)\(\rm Aoki\) 先手时的得分。

转移是显然的,\(\forall v,u\to v\)

\(f_{u,0} = \min(f_{v,1}+w(u,v))\)

\(f_{u,1}= \max(f_{v,0}+w(u,v))\)

如果是 \(\rm DAG\) 拓扑排序就行了,但本题有环,怎么办?

直观的想法是跑 \(\rm dijsktra\),不过是错的,无法保证 \(f_{u,1}\) 取到正确的值。

那么以 \(f_{u,0}\) 为主元(即每次取最小值更新),将 \(f_{u,1}\) 视为辅助转移的。\(\rm dijsktra\) 保证了 \(f_{u,0}\) 能取到正确值。那么对于 \(f_{u,1}\),令 \(\forall u\to v\)\(f_{v,0}\) 都取到正确值后再转移即可。

整体上看,就相当于通过正确的值转移得到其它正确的值(废话)。

如果到最后 \(f_{v,0}\) 尚未取到正确值,则说明 \(f_{v,0}\) 是极大值,依此类推能得到 \(f_{u,1}\) 是极大值这样的。所以若 \(f_{s,0}=inf\) 则最后答案就是 INFINITY

代码

#include<bits/stdc++.h>
using namespace std;

#define int long long
const int N = 2e5 + 5, inf = 1e18;
int n, m, s, f[N][2], u, v, w, chu[N];
bool vis[N][2];
vector<pair<int, int> > to[N];

struct node{int u, f, id;};
inline bool operator < (node A, node B) {return A.f > B.f;}
priority_queue<node> q;

signed main(){
	cin >> n >> m >> s;
	for(int i = 1; i <= m; ++i) scanf("%lld%lld%lld", &u, &v, &w), to[v].push_back({u, w}), ++chu[u];
	for(int i = 1; i <= n; ++i){
		f[i][0] = inf, f[i][1] = -inf;
		if(!chu[i]) q.push({i, f[i][0] = 0, 0}), q.push({i, f[i][1] = 0, 1});
	}
	while(!q.empty()){
		node P = q.top(); q.pop();
		int u = P.u, id = P.id;
		if(vis[u][id]) continue;
		vis[u][id] = true;
		for(auto E : to[u]){
			int v = E.first, w = E.second;
			if(!id){
				--chu[v], f[v][1] = max(f[v][1], f[u][0] + w);
				if(!chu[v] && !vis[v][1]) q.push({v, f[v][1], 1});
			}
			else{
				f[v][0] = min(f[v][0], f[u][1] + w);
				if(!vis[v][0]) q.push({v, f[v][0], 0});
			}
		}
	}
	if(f[s][0] == inf) cout << "INFINITY";
	else cout << f[s][0];
	return 0;
}
posted @ 2026-01-12 19:59  Zwi  阅读(3)  评论(0)    收藏  举报