【bzoj3373】【说谎的牲畜】【差分约束】

来源:互联网 发布:ubuntu禁止自动休眠 编辑:程序博客网 时间:2024/05/07 13:25

Description

兽群中总是有一些麻烦制造者.约翰知道他的N(1≤N≤100)头奶牛中有一头总是说谎,其他的总是说真话.他想快速的找出这个麻烦制造者.为了实现这个目标,他一个一个的问这些奶牛Q(1≤Q≤1000)个关于它们吃草的简单问题(虽然大多数奶牛是诚实的但它们依旧很笨只能懂得一些关于食物的话题).
他将这些问题用以下的格式写了下来:
牛4说:牛5比牛10吃得多
牛6说:牛10比牛7吃得多
牛3说:牛2比牛6吃得多
牛1说:牛7比牛5吃得多
从这个例子中不难看出说谎的奶牛只有可能是4,6,1.你的任务是确定可能说谎的奶牛的个
数.可能说谎的奶牛是指如果这头奶牛说谎则输入数据中不存在矛盾.

Input

第1行:两个用空格分开的整数N和Q.第2到Q+1:每一行描述一个问题,由3个用空格隔开的整数A,B,C表示,意思是A说B牛吃的比C牛多.一头奶牛可能回答多次.

Output

仅一行一个整数即可能说谎的奶牛的头数.

Sample Input

3 4
3 1 2
1 3 1
1 3 2
2 2 1

Sample Output

2

样例说明
3头奶牛给出了4个回答.奶牛1说3>1,3>2,奶牛2说2>1,奶牛3说1>2.当然“>”的意思是“吃得多”. 显然,2号和3号的话是矛盾的.它们都有可能说谎.如果1号说谎则2,3都没说谎,那是不可能的.所以,1号说的一定是实话.
题解:
枚举每一头奶牛.按差分约束系统建图.判断是否存在正权环即可。
代码:
#include<iostream>#include<cstdio>#include<cstring>#define N 110#define M 200010using namespace std;int point[N],cnt,k,x,y,next[M<<1],n,m,ans,dis[N],f[N],q[N*100],c[N];struct edge{int st,en,v;}e[M<<1];struct use{int x[110],y[110],num;}p[N];void add(int x,int y,int v){//cout<<x<<' '<<y<<endl;   next[++cnt]=point[x];point[x]=cnt;   e[cnt].st=x;e[cnt].en=y;e[cnt].v=v;}bool spfa(){  int h(0),t(1);  memset(f,0,sizeof(f));  memset(dis,128,sizeof(dis));  memset(c,0,sizeof(c));  dis[0]=0;q[t]=0;f[0]=1;  while(h<t){    int u=q[++h];f[u]=0;    for (int i=point[u];i;i=next[i])      if (dis[e[i].en]<dis[u]+e[i].v){        dis[e[i].en]=dis[u]+e[i].v;        if (++c[e[i].en]>500) return false;        if (!f[e[i].en]){           f[e[i].en]=1;           q[++t]=e[i].en;        }  }  }  return true;}int main(){  scanf("%d%d",&n,&m);   for (int i=1;i<=m;i++){    scanf("%d%d%d",&k,&x,&y);p[k].x[++p[k].num]=x;    p[k].y[p[k].num]=y;    add(y,x,1);  }  for (int i=1;i<=n;i++) add(0,i,0);  for (int i=1;i<=n;i++){    memset(point,0,sizeof(point));cnt=0;    for (int j=1;j<=p[i].num;j++)      add(p[i].x[j],p[i].y[j],0);    for (int j=1;j<=n;j++)     if (j!=i){       for (int k=1;k<=p[j].num;k++)        add(p[j].y[k],p[j].x[k],1);     }    for (int i=1;i<=n;i++) add(0,i,0);    if (spfa()) ans++;  }  cout<<ans<<endl;}


0 0