[ABC261Ex] Game on Graph 题解
主要来说明一下正确性。
一
转移方程就不写了,大家都会,和其他题解相同,因为不是 DAG,无法直接 dp。这时候一般会考虑使用最短路算法进行转移,但要求是转移都是同号的,如都是
如果我们直接丢到 Dijkstra 里面去做,显然会错,因为我们可能把还没有决策完的一个
按照上面的过程,我们希望对于
为什么是对的呢,因为我们这样操作,相当于做了一步确定主元,我们是以
我们使用了类似递归证明的方法,而这个递归证明是有边界的(出度为
复杂度
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#define int long long
using namespace std;
int n,m,S;
int ind[200005];
int f[200005][2];
bool vis[200005][2];
struct node{int u,ok,d;};
bool operator < (node p,node q){return p.d>q.d;}
priority_queue <node> q;
vector <pair <int,int>> g[200005];
signed main(){
scanf("%lld%lld%lld",&n,&m,&S);
for(int i=1;i<=m;i++){
int u,v,w;
scanf("%lld%lld%lld",&u,&v,&w);
g[v].push_back({u,w});
ind[u]++;
}
for(int i=1;i<=n;i++)
if(ind[i]==0) q.push({i,0,0}),q.push({i,1,0});
else f[i][0]=1e18;
while(!q.empty()){
auto tmp=q.top();
q.pop();
if(vis[tmp.u][tmp.ok]) continue;
vis[tmp.u][tmp.ok]=1;
int u=tmp.u,ok=tmp.ok;
for(auto tmp:g[u]){
int v=tmp.first,w=tmp.second;
if(!ok){
ind[v]--;
f[v][1]=max(f[v][1],f[u][0]+w);
if(!ind[v]) q.push({v,1,f[v][1]});
}
else{
if(f[v][0]>f[u][1]+w){
f[v][0]=f[u][1]+w;
if(!vis[v][0]) q.push({v,0,f[v][0]});
}
}
}
}
if(f[S][0]==1e18) puts("INFINITY");
else printf("%lld\n",f[S][0]);
return 0;
}