[bzoj3436]小K的农场【差分约束系统】【判负环】
【题目链接】
http://www.lydsy.com/JudgeOnline/problem.php?id=3436
【题解】
一道比较裸的差分约束模板题。
当时,向连一条权值为的边。
当时,向连一条权值为的边。
当时,向连一条权值为的边,向连一条权值为的边。
以上所有边的意义为
所以跑一边spfa求是否有求负环即可。
tips:spfa用bfs写TLE,用dfs写能快很多,判断方式是若路径上之前已经出现了这个点,则一定有负环,直接退出。
/* --------------
user Vanisher
problem bzoj-3436
----------------*/
# include <bits/stdc++.h>
# define ll long long
# define inf 0x3f3f3f3f
# define N 10010
using namespace std;
int read(){
int tmp=0, fh=1; char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') fh=-1; ch=getchar();}
while (ch>='0'&&ch<='9'){tmp=tmp*10+ch-'0'; ch=getchar();}
return tmp*fh;
}
int dis[N],use[N],ti[N],q[N],head[N];
struct node{
int data,next,vote;
}e[N*10];
int place,n,m;
void build(int u, int v, int k){
e[++place].data=v; e[place].next=head[u]; head[u]=place; e[place].vote=k;
}
/*bool spfa(){
memset(dis,inf,sizeof(dis));
memset(use,0,sizeof(use));
memset(ti,0,sizeof(ti));
q[1]=0; int pl=1, pr=1; dis[0]=0; use[0]=true;
while (pl<=pr){
int x=q[(pl++)%N];
for (int ed=head[x]; ed!=0; ed=e[ed].next)
if (dis[e[ed].data]>dis[x]+e[ed].vote){
dis[e[ed].data]=dis[x]+e[ed].vote;
if (use[e[ed].data]==false){
ti[e[ed].data]++;
if (ti[e[ed].data]>=n) return 1;
use[e[ed].data]=true;
q[(++pr)%N]=e[ed].data;
}
}
use[x]=false;
}
return 0;
}*/
bool spfa(int x){
use[x]=true;
for (int ed=head[x]; ed!=0; ed=e[ed].next)
if (dis[e[ed].data]>dis[x]+e[ed].vote){
dis[e[ed].data]=dis[x]+e[ed].vote;
if (use[e[ed].data]==true) return true;
if (spfa(e[ed].data)) return true;
}
use[x]=false;
return false;
}
int main(){
n=read(), m=read();
int u,v,k;
for (int i=1; i<=m; i++){
int opt=read();
if (opt==1){
u=read(), v=read(), k=read();
build(u,v,-k);
}
if (opt==2){
u=read(), v=read(), k=read();
build(v,u,k);
}
if (opt==3){
u=read(), v=read();
build(u,v,0);
build(v,u,0);
}
}
for (int i=1; i<=n; i++)
build(0,i,0);
memset(dis,inf,sizeof(dis));
dis[0]=0;
bool flag=spfa(0);
if (flag==1)
printf("No\n");
else printf("Yes\n");
return 0;
}