题目链接:
[POJ 2983]Is the Information Reliable?[差分约束]
题意分析:
给出N个防御站和M个提示,提示P代表A站在B站的北方X米处,提示V代表,A站在B站北方至少1米处,现在问:给出的这M个提示是否可信?
解题思路:
对于P操作,我们得知dis[B] - dis[A] == x 转换为:dis[B] - dis[A] <= x && dis[B] - dis[A] >= x,再根据V,得知:dis[B] - dis[A] >= 1。根据上次说的,写出方程后,写出转移if (dis[B] < dis[A] + 1) dis[B] = dis[A] + 1。可知,是求最长路。如果有矛盾出现的话,就会形成环,这个不妨画图就清楚了:
当出现矛盾时,就会出现不等关系后,必然会造成增得比减的多的情况。上图:1->2->3->1
个人感受:
差分约束,我天= =。只能说这种东西太牛了。。。。我想过并查集或者直接找矛盾,只能说这种方法太6了。。。。然后我太弱了TAT
具体代码如下:
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<string>
#define pr(x) cout << #x << " = " << (x) << '\n';
using namespace std;
const int INF = 0x7f7f7f7f;
const int MAXN = 1e3 + 111;
const int MAXM = 3e5 + 111;
struct Edge{
int next, to, w;
}edge[MAXM];
int head[2 * MAXN], tol;
void addedge(int u, int v, int w) {
edge[tol].next = head[u];
edge[tol].to = v;
edge[tol].w = w;
head[u] = tol++;
}
int dis[MAXN], num[MAXN];
bool in[MAXN];
bool spfa(int n, int s) {
for (int i = 1; i <= n; ++i) {
dis[i] = -INF;
in[i] = num[i] = 0;
addedge(s, i, 0);
}
queue<int> q;
q.push(s);
dis[s] = 0;
in[s] = 1;
++num[s];
while (q.size()) {
int u = q.front(); q.pop();
in[u] = 0;
for (int i = head[u]; ~i; i = edge[i].next) {
int v = edge[i].to;
if (dis[v] < dis[u] + edge[i].w) {
dis[v] = dis[u] + edge[i].w;
if (!in[v]) {
q.push(v);
in[v] = 1;
if (++num[v] > n) return 1;
}
}
}
}
return 0;
}
int main()
{
int n, m, a, b, c;
char op[2];
while (~scanf("%d%d", &n, &m)) {
memset(head, -1, sizeof head);
tol = 0;
for (int i = 0; i < m; ++i) {
scanf("%s%d%d", op, &a, &b);
if (op[0] == 'P') {
scanf("%d", &c);
addedge(a, b, c);
addedge(b, a, -c);
}
else {
addedge(a, b, 1);
}
}
if (spfa(n, 0)) printf("Unreliable\n");
else printf("Reliable\n");
}
return 0;
}