[bzoj3436][差分约束]小K的农场

109 篇文章 4 订阅
2 篇文章 0 订阅

Description

背景 小K是个特么喜欢玩MC的孩纸。。。 描述
小K在MC里面建立很多很多的农场,总共n个,以至于他自己都忘记了每个农场中种植作物的具体数量了,他只记得
一些含糊的信息(共m个),以下列三种形式描述:农场a比农场b至少多种植了c个单位的作物,农场a比农场b至多
多种植了c个单位的作物,农场a与农场b种植的作物数一样多。但是,由于小K的记忆有些偏差,所以他想要知道存
不存在一种情况,使得农场的种植作物数量与他记忆中的所有信息吻合。

Input

第一行包括两个整数n和m,分别表示农场数目和小K记忆中的信息的数目接下来m行:如果每行的第一个数是1,接
下来有三个整数a,b,c,表示农场a比农场b至少多种植了c个单位的作物如果每行第一个数是2,接下来有三个整数a
,b,c,表示农场a比农场b至多多种植了c个单位的作物如果每行第一个数是3,接下来有两个整数a,b,表示农场a
种植的数量与b一样。1<=n,m,a,b,c<=10000

Output

如果存在某种情况与小K的记忆吻合,输出”Yes”,否则输出”No”

Sample Input

3 3
3 1 2
1 1 3 1
2 2 3 2

Sample Output

Yes

HINT

样例解释
三个农场种植的数量可以为(2,2,1)

题解

差分约束一眼题
直接设d[i]为第i个农场种植的作物数
输入x,y,c(c第三种操作可以去掉)
第一种操作 d[y]≥d[x]-c 那么x~y连一条-c的边
第二种操作 d[x]≥d[y]+c 那么y~x连一条c的边
第三种操作 d[x]≥d[y] 且 d[y]≥d[x] 那么x~y和y~x都要一条权为0的边
跑最长路即可,最短路的话吧上面改一下也可以跑。。
记住判环的时候一定要break掉while

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
struct node
{
    int x,y,c,next;
}a[51000];int len,last[51000];
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 d[51000];bool v[51000];
int sta[51000],top,ru[51000];
int n,m;
int main()
{
    scanf("%d%d",&n,&m);
    len=0;memset(last,0,sizeof(last));
    for(int i=1;i<=m;i++)
    {
        int x,y,c,op;
        scanf("%d%d%d",&op,&x,&y);
        if(op==1 || op==2)scanf("%d",&c);
        if(op==1)ins(x,y,-c);
        else if(op==2)ins(y,x,c);
        else ins(y,x,0),ins(x,y,0);
    }
    memset(d,0,sizeof(d));
    memset(ru,0,sizeof(ru));
    top=0;memset(v,true,sizeof(v));
    for(int i=1;i<=n;i++)sta[++top]=i,ru[i]++;
    bool bk=false;
    while(top)
    {
        int x=sta[top--];
        v[x]=false;
        for(int k=last[x];k;k=a[k].next)
        {
            int y=a[k].y;
            if(d[y]<d[x]+a[k].c)
            {
                d[y]=d[x]+a[k].c;
                ru[y]++;
                if(ru[y]>=n){bk=true;break;}
                if(v[y]==false)
                {
                    v[y]=true;
                    sta[++top]=y;
                }
            }
        }
        if(bk==true)break;//这里一定要break,因为上面那个break只是跳出if的。。 
    }
    if(bk==false)printf("Yes\n");
    else printf("No\n");
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值