[ABC261Ex] Game on Graph
Problem Statement
We have a directed graph with \(N\) vertices and \(M\) edges. Edge \(i\) is directed from Vertex \(A_i\) to \(B_i\).and has a weight of \(C_i\).
Initially, there is a piece on Vertex \(v\). Takahashi and Aoki will play a game where they alternate turns moving the piece as follows:
- If there is no edge that goes from the vertex on which the piece is placed, end the game.
- If there are edges that go from the vertex on which the piece is placed, choose one of those edges and move the piece along that edge.
Takahashi goes first. Takahashi tries to minimize the total weight of the edges traversed by the piece, and Aoki tries to maximize it.
More formally, their objectives are as follows.
Takahashi gives the first priority to ending the game in a finite number of moves. If this is possible, he tries to minimize the total weight of the edges traversed by the piece.
Aoki gives the first priority to preventing the game from ending in a finite number of moves. If this is impossible, he tries to maximize the total weight of the edges traversed by the piece.
(If the piece traverses the same edge multiple times, the weight is added that number of times.)
Determine whether the game ends in a finite number of moves when both players play optimally. If it ends, find the total weight of the edges traversed by the piece.
Constraints
- \(1≤N≤2×10^5\)
- \(0≤M≤2×10^5\)
- \(1\le v≤N\)
- \(1≤A_i,B_i≤N\)
- There is no multi-edges. That is, \((A_i,B_i)\ne (A_j,B_j)\) for \(i\ne j\)
- There is no self-loops. That is, \(A_i\ne B_i\).
- \(0≤C≤10 ^9\)
- All values in input are integers.
Input
Input is given from Standard Input in the following format:
\(N\) \(M\) \(v\)
\(A_1\) \(B_1\) \(C_1\)
\(A_2\) \(B_2\) \(C_2\)
⋮
\(A_M\) \(B_M\) \(C_M\)
Output
If the game does not end in a finite number of moves when both players play optimally, print INFINITY.
If the game ends in a finite number of moves, print the total weight of the edges traversed by the piece.
Sample Input 1
7 6 1
1 2 1
1 3 10
2 4 100
2 5 102
3 6 20
3 7 30
Sample Output 1
40
First, Takahashi will move the piece to Vertex \(3\). Next, Aoki will move the piece to Vertex \(7\), and the game will end.
The total weight of the edges traversed by the piece will be \(10+30=40\).
Sample Input 2
3 6 3
1 2 1
2 1 2
2 3 3
3 2 4
3 1 5
1 3 6
Sample Output 2
INFINITY
The game will not end in a finite number of moves.
Sample Input 3
4 4 1
1 2 1
2 3 1
3 1 1
2 4 1
Sample Output 3
5
The piece will go \(1→2→3→1→2→4\).
假设图是一个有向无环图,那么直接使用 DAG 上 dp 即可。轮到 Alice 时在所有后继节点中取最小值。轮到 Bob 时在所有后继节点中取最大值。
那么如果是有环呢?有环的 min/max dp 的经典解法是跑最短路。把无后继的节点入堆,图建成反图,跑 dij 就行了。
但是这个 dp 有时候取最大值,有时候取最小值,好像很难处理。
首先如果轮到 Alice 的话,直接取最小值。因为 dij 的堆用小根堆,所以Alice的dp值直接跑dij是正确的。
但是如果轮到 Bob,他的值不像 Alice,需要所有的后继节点更新后,才能更新 Bob 的dp值。而且他是希望可以在博弈中跑出死循环的,所以如果不是所有的后继节点都更新得到,他就不更新。我们可以使用类似拓扑的方式处理。记录入度,然后松弛时入度减一。
那么想清楚代码就很好写了。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=2e5+5;
struct node{
int v,k;
LL w;
bool operator<(const node&n)const{
return w>n.w;
}
};
struct edge{
int v,nxt,w;
}e[N<<1];
int hd[N],n,m,s,u,v,w,e_num,in[N],vis[N][2];
LL dis[N][2];
priority_queue<node>q;
void add_edge(int u,int v,int w)
{
e[++e_num]=(edge){v,hd[u],w};
hd[u]=e_num;
}
void dijkstra()
{
for(int i=1;i<=n;i++)
{
if(!in[i])
{
q.push((node){i,0,0});
q.push((node){i,1,0});
}
else
dis[i][0]=0x7f7f7f7f7f7f7f7f;
}
// printf("%d\n",dis[1][0]);
while(!q.empty())
{
int v=q.top().v,k=q.top().k;
// printf("%d %d %d\n",v,k,dis[v][k]);
q.pop();
if(vis[v][k])
continue;
if(k)
{
for(int i=hd[v];i;i=e[i].nxt)
{
// if(v==2)
// printf("%d %d %d\n",e[i].v,dis[v][1]+e[i].w,dis[e[i].v][0]);
if(dis[v][1]+e[i].w<dis[e[i].v][0])
{
dis[e[i].v][0]=dis[v][1]+e[i].w;
q.push((node){e[i].v,0,dis[e[i].v][0]});
}
}
}
else
{
for(int i=hd[v];i;i=e[i].nxt)
{
in[e[i].v]--;
if(dis[v][0]+e[i].w>dis[e[i].v][1])
{
dis[e[i].v][1]=dis[v][0]+e[i].w;
// q.push((node){e[i].v,1,-dis[e[i].v][1]});
}
if(!in[e[i].v])
q.push((node){e[i].v,1,dis[e[i].v][1]});
}
}
}
}
int main()
{
scanf("%d%d%d",&n,&m,&s);
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&w),in[u]++;
add_edge(v,u,w);
}
dijkstra();
if(dis[s][0]>1e18)
printf("INFINITY");
else
printf("%lld",dis[s][0]);
}