zoukankan      html  css  js  c++  java
  • 小K的农场

    小K的农场

    题目描述

    小K在MC里面建立很多很多的农场,总共n个,以至于他自己都忘记了每个农场中种植作物的具体数量了,他只记得一些含糊的信息(共m个),以下列三种形式描述:

    • 农场a比农场b至少多种植了c个单位的作物,
    • 农场a比农场b至多多种植了c个单位的作物,
    • 农场a与农场b种植的作物数一样多。

    但是,由于小K的记忆有些偏差,所以他想要知道存不存在一种情况,使得农场的种植作物数量与他记忆中的所有信息吻合。

    输入输出格式

    输入格式:

    第一行包括两个整数 n 和 m,分别表示农场数目和小 K 记忆中的信息数目。

    接下来 m 行:

    如果每行的第一个数是 1,接下来有 3 个整数 a,b,c,表示农场 a 比农场 b 至少多种植了 c 个单位的作物。

    如果每行的第一个数是 2,接下来有 3 个整数 a,b,c,表示农场 a 比农场 b 至多多种植了 c 个单位的作物。如果每行的第一个数是 3,接下来有 2 个整数 a,b,表示农场 a 种植的的数量和 b 一样多。

    输出格式:

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

    输入输出样例

    输入样例#1:

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

    输出样例#1:

    Yes

    说明

    对于 100% 的数据保证:(1 ≤ n,m,a,b,c ≤ 10000.)

    题解

    看到题目中的三个条件,应该可以看出这是一道差分约束题了

    首先抛开题目,如果一个式子满足

    [dis[j]>=dis[i]+w[i,j] ]

    应该可以想到最长路的三角不等式

    对于一条边(u,v,w),我们认为v点的值需要至少比u点大w

    所以对于1条件,可以简化为(dis[a]>=dis[b]+c),我们建一条由b到a的边,边权为c

    对于2条件,(dis[a]<=dis[b]+c),转化为(dis[b]>=dis[a]-c),建一条由a到b的边,边权为-c

    对于3条件,(dis[a]=dis[b]),建双向边(a,b),边权为0

    其次,为了保证图联通,我们吧每个节点向0点建一条边权为0的边
    所以数组就要开3倍!!!!!

    然后跑最短路就可以了,SPFA判环,最长路判正环,最短路判负环,没什么要注意的了

    Code

    #include<bits/stdc++.h>
    #define rg register
    #define Min(a,b) (a)<(b)?(a):(b)
    using namespace std;
    const int N=10010,M=10010;
    const int inf=2e9;
    
    int in(int &ans)
    {
        ans=0; int f=1; char i=getchar();
        while(i<'0' || i>'9') {if(i=='-') f=-1; i=getchar();}
        while(i>='0' && i<='9') ans=(ans<<1)+(ans<<3)+i-'0', i=getchar();
        ans*=f;
    }
    
    bool flag;
    int cnt,n,m,T;
    int to[M<<2],nex[M<<2],w[M<<2],head[N],dis[N],vis[N];
    
    inline void add(int a,int b,int c)
    {
        to[++cnt]=b,nex[cnt]=head[a];
        w[cnt]=c,head[a]=cnt;
    }
    
    void SPFA(int u)
    {
        vis[u]=1;
        for(int i=head[u];i;i=nex[i]) {
    	if(dis[to[i]]<dis[u]+w[i]) {
    	    if(vis[to[i]]||flag) {flag=1;break;}
    	    dis[to[i]]=dis[u]+w[i];
    	    SPFA(to[i]);
    	}
        }vis[u]=0;
    }
    
    int main()
    {
        in(n),in(m);
        for(int i=1;i<=m;i++) {
    	int op,a,b,c;
    	in(op);
    	switch(op){
    	case 1:in(a),in(b),in(c),add(b,a,c);break;
    	case 2:in(a),in(b),in(c),add(a,b,-c);break;
    	case 3:in(a),in(b),add(a,b,0),add(b,a,0);break;
    	}
        }
        for(int i=1;i<=n;i++) add(0,i,0);
        for(int i=1;i<=n;i++) dis[i]=-inf;
        SPFA(0); puts((!flag)?"Yes":"No");
        return 0;
    }
    

    博主蒟蒻,随意转载.但必须附上原文链接

    http://www.cnblogs.com/real-l/

  • 相关阅读:
    【.NET深呼吸】Zip文件操作(1):创建和读取zip文档
    【Win10 应用开发】实现数据的增量加载
    【Win10 应用开发】使用“实时可视化树”工具查看应用界面元素
    将中文字符串分割为数组 解决str_split中文乱码php
    Mac搭建PHP+rabbitMQ环境
    常用笔记:PHP
    常用笔记:MySQL
    常用笔记:Linux
    常用笔记:Web前端
    常用笔记:工具使用
  • 原文地址:https://www.cnblogs.com/real-l/p/9547725.html
Copyright © 2011-2022 走看看