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

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 200010
using 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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值