洛谷P1993 小K的农场

思路是差分约束+dfs版SPFA。

首先来思考差分约束的过程,将题目给出的式子进行转化:

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

SPFA我们考虑跑最短路,那么要让SPFA中满足的式子就是if(d[b]>d[a]-c)d[b]=d[a]-c,即让b<=a-c。

所以建一条a->b权值为-c的边,使d[b]始终满足<=d[a]-c。

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

同理,建一条b->a,权值为c的边。

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

建一条a,b间的双向边,权值为0。即建两条单向权值为0的边。

最后处理完所有条件,考虑存在整张图不连通的情况——这时候我们需要一个点能把整张图串起来,又不会影响到结果,即“超级源点”0点。

由0点向每个点建一条权值为0的边。

然后就是SPFA松弛,判负环的过程。这里用dfs版的SPFA不然会T。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
int n,m,d[10001],vis[10001],cnt[10001],flag;
int ver[50001],Next[50001],edge[50001],head[10001],tot;
queue<int>q; 
void add(int a,int b,int c){
    ver[++tot]=b;
    Next[tot]=head[a];
    edge[tot]=c;
    head[a]=tot;
}
int spfa(int x){
    vis[x]=1;
    for(int i=head[x];i;i=Next[i]){
        int v=ver[i],z=edge[i];
        if(d[v]>d[x]+z){
            d[v]=d[x]+z;
            if(vis[v])return 0;
            if(!spfa(v))return 0;
        }
    }
    vis[x]=0;
    return 1;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1,k,a,b,c;i<=m;i++){
        scanf("%d",&k);
        if(k==1){
            scanf("%d%d%d",&a,&b,&c);
            add(a,b,-c);
        }
        if(k==2){
            scanf("%d%d%d",&a,&b,&c);
            add(b,a,c);
        }
        if(k==3){
            scanf("%d%d",&a,&b);
            add(a,b,0);
            add(b,a,0);
        }
    }
    for(int i=1;i<=n;i++)add(0,i,0);
    memset(d,0x3f,sizeof(d));
    d[0]=0;
    if(!spfa(0))printf("No");
    else printf("Yes");
    return 0;
 } 
原文地址:https://www.cnblogs.com/chloris/p/10484354.html