luogu1993 小K的农场

题目大意

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

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

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

差分约束

要处理一组类似$x_{i1}+k_igeq x_{i2}$的形式的偏序关系,我们发现图上每条边e连接的两个结点的单源最短路径长度都满足u[e]+w[e]>=v[e](u可能在v的最短路径上,也可能不在)。所以我们将图上的结点$x_{i1}, x_{i2}$连一条长度为$k_i$的边,将原点与所有边相连,跑一下最短路,那么每个结点的dist就是其所对应$x$值的一个解。

无解当且仅当图中有负环,判断负环的方法可以为:在SPFA时,判断每个结点的最短路径所经过的结点的数量是否超过TotNode,超过了则说明有负环。

题解说明

使用STL里的queue维护Node*,在BZOJ上可以AC,在洛谷上由于评测机64位指针8子节导致RE;queue改为维护int原先RE变为TLE,开O2后AC,不开O2即使手写queue也没有卵用。据说有用Dfs实现的SPFA,但是我不会。

// luogu-judger-enable-o2
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;

const int MAX_NODE = 10010, MAX_EDGE = MAX_NODE * 3, INF = 0x3f3f3f3f;

struct Node;
struct Edge;

struct Node
{
    Edge *Head;
    int Dist, FromEdgeCnt;
    bool Inq;
}_nodes[MAX_NODE];
int _vCount;

struct Edge
{
    Node *To;
    Edge *Next;
    int Weight;
}_edges[MAX_EDGE];
int _eCount;

void AddEdge(int uId, int vId, int w)
{
    Node *u = _nodes + uId, *v = _nodes + vId;
    Edge *e = _edges + ++_eCount;
    e->Weight = w;
    e->To = v;
    e->Next = u->Head;
    u->Head = e;
}

bool SPFA(Node *start)
{
    for (int i = 1; i <= _vCount; i++)
        _nodes[i].Dist = INF;
    start->Dist = 0;
    start->FromEdgeCnt = 0;
    start->Inq = true;
    static queue<int> q;
    q.push(start - _nodes);
    while (!q.empty())
    {
        int curId = q.front();
        q.pop();
        Node *cur = _nodes + curId;
        cur->Inq = false;
        if (cur->FromEdgeCnt > _vCount)
            return false;
        for (Edge *e = cur->Head; e; e = e->Next)
        {
            if (cur->Dist + e->Weight < e->To->Dist)
            {
                e->To->Dist = cur->Dist + e->Weight;
                e->To->FromEdgeCnt = cur->FromEdgeCnt + 1;
                if (!e->To->Inq)
                {
                    e->To->Inq = true;
                    q.push(e->To - _nodes);
                }
            }
        }
    }
    return true;
}

int main()
{
    int qCnt;
    _eCount = 0;
    scanf("%d%d", &_vCount, &qCnt);
    _vCount++;
    for (int i = 1; i <= qCnt; i++)
    {
        int op, a, b, c;
        scanf("%d", &op);
        switch (op)
        {
        case 1:
            scanf("%d%d%d", &a, &b, &c);
            AddEdge(a, b, -c);
            break;
        case 2:
            scanf("%d%d%d", &a, &b, &c);
            AddEdge(b, a, c);
            break;
        case 3:
            scanf("%d%d", &a, &b);
            AddEdge(a, b, 0);
            AddEdge(b, a, 0);
            break;
        }
    }
    for (int i = 1; i <= _vCount - 1; i++)
        AddEdge(_vCount, i, 0);
    if (SPFA(_nodes + _vCount))
        printf("Yes
");
    else
        printf("No
");
    return 0;
}

  

原文地址:https://www.cnblogs.com/headboy2002/p/9388100.html