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

    洛咕

    题意:小K总共有(n(n<=50000))个农场,以至于他自己都忘记了每个农场中种植作物的具体数量了,他只记得一些含糊的信息(共m个),以下列三种形式描述:

    - 农场a比农场b至少多种植了c个单位的作物,

    - 农场a比农场b至多多种植了c个单位的作物,

    - 农场a与农场b种植的作物数一样多。

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

    三种形式其中第一种形如(X_a-X_b>=c),第二种形如(X_a-X_b<=c),第三种是等式形如(X_a-X_b=0).题目给定n个这样的不等式或者等式,很容易想到要用差分约束来做.

    对于第一种等式,我们将其转化成(X_b-X_a<=-c),然后连一条a到b的权值为-c的有向边,对于第二种等式,不用转化,直接连一条从b到a的权值为c的有向边,对于第三种等式,连一条权值为0的a,b之间的无向边.

    然后差分约束的套路都是,新建立一个节点0,然后分别向其余n个点连一条权值为0的有向边.

    建图之后,从0开始跑spfa求最短路,同时判断负环.众所周知,spfa判断负环有各种玩法.下面第一份代码是中规中矩的spfa判负环,需要吸口氧才能过.第二份代码是铤而走险的做法,具体见代码注释.

    // luogu-judger-enable-o2
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<map>
    #include<set>
    #define ll long long
    using namespace std;
    inline int read(){
        int x=0,o=1;char ch=getchar();
        while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
        if(ch=='-')o=-1,ch=getchar();
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*o;
    }
    const int N=50005;
    int n,m,dis[N],visit[N],cnt[N],sum[N];
    int tot,head[N],to[N],nxt[N],w[N];
    inline void add(int a,int b,int c){
    	nxt[++tot]=head[a];head[a]=tot;
    	to[tot]=b;w[tot]=c;
    }
    queue<int>q;
    inline int spfa(){
    	memset(dis,0x3f,sizeof(dis));
    	dis[0]=0;visit[0]=1;q.push(0);++sum[0];
    	while(q.size()){
    		int x=q.front();q.pop();visit[x]=0;
    		for(int i=head[x];i!=-1;i=nxt[i]){
    			int y=to[i],z=w[i];
    			if(dis[y]>dis[x]+z){
    				dis[y]=dis[x]+z;
    				cnt[y]=cnt[x]+1;if(cnt[y]>=n)return 0;
    //cnt[y]表示从0到y的最短路径包含的边数,若大于等于n,则判断有负环
    				if(!visit[y]){
    					++sum[y];if(sum[y]>=n)return 0;
    //sum[y]表示点y入队的次数,若大于等于n,也判断有负环,这个超级低效
    					q.push(y);visit[y]=1;
    				}
    			}
    		}
    	}
    	return 1;
    }
    int main(){
    	n=read();m=read();memset(head,-1,sizeof(head));
    	for(int i=1;i<=m;++i){
    		int opt=read(),a=read(),b=read();
    		if(opt==1){int val=read();add(a,b,-val);}
    		if(opt==2){int val=read();add(b,a,val);}
    		if(opt==3){add(a,b,0);add(b,a,0);}
    	}
    	for(int i=1;i<=n;++i)add(0,i,0);
    	if(spfa())puts("Yes");
    	else puts("No");
        return 0;
    }
    

    因为只有判断负环的一出代码优化了,所以只放spfa的代码,其余都没变动.

    queue<int>q;
    inline int spfa(){
    	memset(dis,0x3f,sizeof(dis));
    	dis[0]=0;visit[0]=1;q.push(0);++sum;
    	while(q.size()){
    		int x=q.front();q.pop();visit[x]=0;
    		for(int i=head[x];i!=-1;i=nxt[i]){
    			int y=to[i],z=w[i];
    			if(dis[y]>dis[x]+z){
    				dis[y]=dis[x]+z;
    				cnt[y]=cnt[x]+1;if(cnt[y]>=n)return 0;//同上
    				if(!visit[y]){
    					++sum;if(sum>=N)return 0;
    //sum表示所有点入队的总次数,我就随便搞了一个稍微大一点的数来判断,跑得飞快
    //然后这个判断是有一定风险型的,有可能出现错误判断.
    					q.push(y);visit[y]=1;
    				}
    			}
    		}
    	}
    	return 1;
    }
    
  • 相关阅读:
    css中的背景、渐变 文本格式化和表格的常用属性
    HTML5中常见的英文单词
    matlab文件处理
    优先级队列
    编程珠玑(一)
    排序算法之希尔排序
    自己写的矩阵类Matrix
    排序算法之快速排序
    Thoughtworks公司面试题——MARS ROVERS问题
    matlab画图
  • 原文地址:https://www.cnblogs.com/PPXppx/p/11383185.html
Copyright © 2011-2022 走看看