洛谷 P1993 小 K 的农场 (差分约束)

题面

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

农场 a 比农场 b 至少多种植了 c 个单位的作物;
农场 a 比农场 b 至多多种植了 c 个单位的作物;
农场 a 与农场 b 种植的作物数一样多。
但是,由于小 K 的记忆有些偏差,所以他想要知道存不存在一种情况,使得农场的种植作物数量与他记忆中的所有信息吻合。

输入格式
第一行包括两个整数 nn 和 mm,分别表示农场数目和小 K 记忆中的信息数目。

接下来 mm 行:

如果每行的第一个数是 11,接下来有三个整数 a,b,ca,b,c,表示农场 aa 比农场 bb 至少多种植了 cc 个单位的作物;
如果每行的第一个数是 22,接下来有三个整数 a,b,ca,b,c,表示农场 aa 比农场 bb 至多多种植了 cc 个单位的作物;
如果每行的第一个数是 33,接下来有两个整数 a,ba,b,表示农场 aa 种植的的数量和 bb 一样多。
输出格式
如果存在某种情况与小 K 的记忆吻合,输出 Yes,否则输出 No

思路

显然我们可以根据题目的意思很显然的列出一组不等式的约束关系,然后我们就可以使用差分约束将这些约束关系转换成为图里面的点的最短路关系,所以我们对这些约束关系进行加边,完事之后跑一边bell-man或者spfa判断负环的存在就好了。讲一下差分的入门吧,题目往往会给你一组约束关系,满足一些不等式关系,那么我们把它化成Xi<=Xj+w的形式,那么你看出什么了么?没错,最短路的关系,对于一个点和他联结的前一个点,题目的最短路关系都满足这样的条件,所以我们把这些约束关系都转换成这样的形式,然后对这些关系都进行一个图化(加边操作),完事之后如果每个点的最短路都可以唯一确定也就是方程存在解,那么我们说这个差分约束可以被满足,反之就不行,因为如果存在负环,那么是不可能有确定的最短路的。

代码实现

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int maxn=10005;
typedef long long ll;
int vis[maxn],head[maxn],cnt,tot[maxn];
int n,m;
ll ans,dis[maxn];
struct edge {
    int v,w,next;
    edge (int v=0, int w=0, int next=0) :v(v), w(w), next (next) {}
}e[maxn];
inline void add (int u,int v,int w) {
   e[++cnt]=edge (v, w, head[u]);
   head[u]=cnt;
}
inline void init () {
    memset (vis,0,sizeof (vis));
    memset (head,-1,sizeof (head));
    memset (tot,0,sizeof (tot));
    memset (dis,0x3f3f3f3f,sizeof (dis));
    cnt=0;
}
inline void spfa (int st) {
   queue<int > q;
   vis[st]=1;
   dis[st]=0;
   q.push (st);
   while (!q.empty()) {
       int u=q.front ();
       vis[u]=0;
       q.pop ();
       for (int i=head[u];i!=-1;i=e[i].next) {
           int v=e[i].v;
           if (dis[v]>dis[u]+e[i].w) {
               dis[v]=dis[u]+e[i].w;
               if (!vis[v]) {
                   vis[v]=1;
                   q.push (v);
                   tot[e[i].v]++;
                   if (tot[e[i].v]>=n) {
                       cout<<"No"<<endl;
                       return ;
                   }
               }
           }
       }
   }
    cout<<"Yes"<<endl;
    return ;
}
int main () {
    while (cin>>n>>m) {
        init ();
        for (int i=1,x,y,z,op;i<=m;i++) {
            cin>>op;
            if (op==1) {
                cin>>x>>y>>z;
                add (x,y,-z);
            }
            else if (op==2) {
                cin>>x>>y>>z;
                add (y,x,z);
            }
            else if (op==3) {
               cin>>x>>y;
               add (x,y,0);
               add (y,x,0);
            }
        }
        spfa (0);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/hhlya/p/13292637.html