传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2330
差分约束系统的裸题啊,十分推荐这篇blog http://blog.csdn.net/consciousman/article/details/53812818
大概的说一下原理就是把不等式组关系转化成图然后跑spfa通过spfa算法里面的“松弛”操作来求解不等式组。
那么了解了这个算法之后这道题就蛮简单的了,可以把五种操作分别对应的不等式列出来建边。
但是有许多的坑点。
第一:边目录的大小要开到N*4(这个应该是我失了智卡了好久)
第二:这个题目数据有一个是有一条长度为十万的链,直接spfa会T飞,有几种做法可以解决这个问题
1、如果直接建立边目录的话会超时,但是可以倒着建。这个是黄学长的玄学做法,应该是面向数据编程(雾
2、如果用spfa判环的话那就是一个点进栈超过n次就出现环了(这题有st就是n+1次),但是数据应该没有这么极端(笑)所以可以判断进栈超过n/k(1<=k<=10)就判环,可以节省时间,也是是面向数据编程(雾
3、比较正统的用强连通缩点做法可以看这篇 http://blog.csdn.net/Leo_h1104/article/details/74627137
code:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn=100010;
struct node
{
int x,y,c,next;
}a[maxn*5]; int len,last[maxn];
void ins(int x,int y,int c)
{
len++;
a[len].x=x;a[len].y=y;a[len].c=c;
a[len].next=last[x];last[x]=len;
}
int st,ed;
long long d[maxn]; bool vis[maxn];
int list[maxn*2],head,tail;
int times[maxn];
int n,m;
queue<int> Q;
bool spfa()
{
int i,t;
vis[0]=1;
Q.push(0);
while(!Q.empty())
{
t=Q.front();
Q.pop();
vis[t]=0;
for(i=last[t];i;i=a[i].next)
{
if(d[t]+a[i].c>d[a[i].y])
{
d[a[i].y]=d[t]+a[i].c;
if(++times[a[i].y]>n) return false;
if(!vis[a[i].y])
{
vis[a[i].y]=1;
Q.push(a[i].y);
}
}
}
}
return true;
}
;
int main()
{
scanf("%d%d",&n,&m);
len=0; memset(last,0,sizeof(last));
for(int i=1;i<=m;i++)
{
int op,x,y;
scanf("%d%d%d",&op,&x,&y);
if(op==1) ins(x,y,0),ins(y,x,0);
else if(op==2)
{
if(x==y)
{
printf("-1\n");
return 0;
}
ins(x,y,1);
}
else if(op==3) ins(y,x,0);
else if(op==4)
{
if(x==y)
{
printf("-1\n");
return 0;
}
ins(y,x,1);
}
else if(op==5) ins(x,y,0);
}
for(int i=n;i>0;i--) ins(0,i,1);
long long ans=0;
if(!spfa())
{
printf("-1\n");
return 0;
}
for(int i=1;i<=n;i++) ans+=d[i];
printf("%lld\n",ans);
return 0;
}