差分约束:把给出的所有约束条件改成形如a-b>=x的形式
x=1:d[a]==d[b],有 d[a]-d[b]>=0, d[b]-d[a]>=0
x=2:d[a]<d[b],有 d[b]-d[a]>=1
x=3:d[a]>=d[b],有 d[a]-d[b]>=0
x=4:d[a]>d[b],有 d[a]-d[b]>=1
x=5:d[a]<=d[b],有 d[b]-d[a]>=0
依照这个建边就可以了。
刚开始把所有点都放进队列里,dis的初始值要都设成1(因为题目中要求每个小朋友都需要有糖果)
如果想加附加源的话要逆着加边,否则超时(我也不知道为啥。。)
要判断一下图是否存在着环(如果一个点被松弛超过n次则存在环)
跑最长路后所有点的dis值之和即为答案。
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=100005;
int n,m;
long long ans;
int to[N*4],nxt[N*4],w[N*4],lj[N],cnt;
void insert(int f,int t,int p)
{
to[++cnt]=t;
nxt[cnt]=lj[f];
lj[f]=cnt;
w[cnt]=p;
}
int d[N],q[N*5],cir[N];
bool inq[N];
bool spfa()
{
for(int i=1;i<=n;i++) q[i]=i,d[i]=1,inq[1]=true,cir[i]=1;
int h=1,t=n,x,j;
while(h!=t+1)
{
x=q[h];
inq[x]=false;
for(int i=lj[x];i;i=nxt[i])
{
j=to[i];
if(d[x]+w[i]>d[j])
{
d[j]=d[x]+w[i];
if(++cir[j]>=n) return false;
if(!inq[j])
{
q[++t]=j;
if(t==N) t=0;
inq[j]=true;
}
}
}
h++;
if(h==N) h=0;
}
return true;
}
int main()
{
scanf("%d%d",&n,&m);
int o,a,b;
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&o,&a,&b);
switch(o)
{
case 1:insert(a,b,0),insert(b,a,0);break;
case 2:if(a==b){printf("-1");return 0;}
insert(a,b,1);break;
case 3:insert(b,a,0);break;
case 4:if(a==b){printf("-1");return 0;}
insert(b,a,1);break;
case 5:insert(a,b,0);break;
}
}
if(!spfa()) {printf("-1");return 0;}
for(int i=1;i<=n;i++) ans+=d[i];
printf("%lld",ans);
}