luogu1993 小K的农场
题目大意
小K在MC里面建立很多很多的农场,总共n个,以至于他自己都忘记了每个农场中种植作物的具体数量了,他只记得一些含糊的信息(共m个),以下列三种形式描述:
- 农场a比农场b至少多种植了c个单位的作物,
- 农场a比农场b至多多种植了c个单位的作物,
- 农场a与农场b种植的作物数一样多。
但是,由于小K的记忆有些偏差,所以他想要知道存不存在一种情况,使得农场的种植作物数量与他记忆中的所有信息吻合。
差分约束
要处理一组类似$x_{i1}+k_i\geq 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\n"); else printf("No\n"); return 0; }