題目連結:[POJ 3169]Layout[差分約束][最短路]
題意分析:
牛兒們互相間有喜歡雙方的,也有討厭雙方的。互相喜歡的,希望離得盡量近,互相討厭的,希望離得盡量遠,問:能否根據要求把牛兒們排成一行。如果能,請輸出1到N的最大距離(如果為無窮輸出『-2』),否則,輸出『-1』。
解題思路:
a喜歡b,那麼 dis(a,b)<=c dis(a, b) ,a討厭b,那麼 dis(a,b)>=c dis(a,b) >= c。
感覺如圖這個範例特別好:
那麼就有 dis(a,c)=max(dis(a,b)+dis(b,c),dis(a,c)) dis(a,c) = max(dis(a,b) + dis(b,c), dis(a, c))
兩隻牛互相討厭的情況,只需兩邊同時乘-1就變成上面這種情況了。
轉換之後也就是變成最短路問題,用最大值作為邊進行最短路。
個人感受:
腦袋裡都是這個範例XD
具體代碼如下:
#include<cstdio>#include<cstring>using namespace std;const int INF = 0x7f7f7f7f;const int MAXN = 1e3 + 11;struct Edge{ int to, next, w;}edge[2 * MAXN * MAXN];int head[MAXN], cnt, dis[MAXN], put_in[MAXN], sta[MAXN], n;bool in[MAXN];void add_edge(int from, int to, int w){ edge[cnt].to = to; edge[cnt].w = w; edge[cnt].next = head[from]; head[from] = cnt++;}bool spfa(int s){ dis[s] = 0; int top = 0; sta[top++] = s; in[s] = 1; while (top) { int cur = sta[--top]; in[cur] = 0; for (int i = head[cur]; ~i; i = edge[i].next) { Edge &e = edge[i]; if (dis[e.to] > dis[cur] + e.w) { dis[e.to] = dis[cur] + e.w; if (!in[e.to]) { in[e.to] = 1; ++put_in[e.to]; if (put_in[e.to] > n) return 0; // 不存在 sta[top++] = e.to; } } } } return 1;}int main(){ int ml, md; scanf("%d%d%d", &n, &ml, &md); memset(head, -1, sizeof(int)*(n + 2)); memset(dis, 0x7f, sizeof(int)*(n + 2)); memset(put_in, 0, sizeof(int)*(n + 2)); memset(in, 0, sizeof(bool)*(n + 2)); cnt = 0; int a, b, d; for (int i = 0; i < ml; ++i) { scanf("%d%d%d", &a, &b, &d); add_edge(a, b, d); } for (int i = 0; i < md; ++i) { scanf("%d%d%d", &a, &b, &d); add_edge(b, a, -d); } if (spfa(1)) printf("%d\n", (dis[n] == INF ? -2 : dis[n])); else puts("-1"); return 0;}