差分约束
裸的差分约束,没什么好说的。大概说一下DFS版的SPFA为什么可以找得到负环。
前提是每一个点都被访问到至少一次。
一个负环上一定存在一个点p,使得从p开始绕着环走出来的距离总是负数。
反证,即假设每一个点出发绕环走都存在一次让走的距离为正,则可以构造一种方案使得可以无限次绕环走而总是非负,显然与负环矛盾。
然后随便设一个源点向每一个点连边判SPFA负环即可。
#include<bits/stdc++.h>
#define N 10005
using namespace std;
namespace runzhe2000
{
int n, m, last[N], ecnt, dis[N], inq[N];
struct edge{int next, to, val;}e[N<<2];
void addedge(int a, int b, int c)
{
e[++ecnt] = (edge){last[a], b, c};
last[a] = ecnt;
}
void SPFA(int x)
{
inq[x] = 1;
for(int i = last[x]; i; i = e[i].next)
{
int y = e[i].to;
if(dis[x] + e[i].val < dis[y])
{
dis[y] = dis[x] + e[i].val;
if(inq[y]){puts("No");exit(0);}
SPFA(y);
}
}
inq[x] = 0;
}
void main()
{
scanf("%d%d",&n,&m);
for(int i = 1; i <= m; i++)
{
int type, a, b, c; scanf("%d",&type);
if(type == 1)
{
scanf("%d%d%d",&a,&b,&c);
addedge(a, b, -c);
}
else if(type == 2)
{
scanf("%d%d%d",&a,&b,&c);
addedge(b, a, c);
}
else
{
scanf("%d%d",&a,&b);
addedge(a, b ,0); addedge(b, a, 0);
}
}
for(int i = 1; i <= n; i++) addedge(n+1, i, 0);
memset(dis,63,sizeof(dis)); dis[n+1] = 0; SPFA(n+1); puts("Yes");
}
}
int main()
{
runzhe2000::main();
}