[POJ3169] Layout
设第i号牛的位置为d[i]。
题目相当于给出了三个约束条件:
- d[i] <= d[i+1]
- d[AL] + DL >= d[BL]
- d[AD] + DD <= d[BD]
恰好可以用最短路模型来解答。因为在这样的问题当中 d[e[i].u]+e[i].w <= d[e[i].v] 刚好和上面的不等式形式相同。这样的问题还有个名字叫做差分约束。
因此在i 和 i+1 之间建长度为0的边,AL 和 BL之间建立长度为 DL 的边,AD和BD之间建立长度为 -DD 的边(移项可知),对于这个图再跑一遍SPFA,求出d[n]即可。(不能用dijkstra是因为里面有负权边)
判断负权边的方法是看更新次数是否已经超过了总边数。
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; const int INF = 1<<30; int N,ML,MD; int AL,BL,DL; int AD,BD,DD; int d[1005]; bool inq[1005]; struct Edge { int v,next,w; }e[20005]; int front[1005]; int cnt = 0; void AddEdge(int u,int v,int w) { e[++cnt].v = v; e[cnt].w = w; e[cnt].next = front[u]; front[u] = cnt; } bool flag = false; void spfa() { queue<int> q; for (int i = 1; i <= N; i++) d[i] = INF; memset(inq,0,sizeof inq); q.push(1); inq[1] = 1,d[1] = 0; int cntt = 1; while(!q.empty()) { cntt++; if(cntt > N+ML+MD) { flag = true; break; } int xx = q.front(); q.pop(); inq[xx] = 0; for (int i = front[xx];i;i = e[i].next) { if(d[e[i].v] > e[i].w + d[xx]) { d[e[i].v] = e[i].w + d[xx]; if(!inq[e[i].v]) { inq[e[i].v] = 1; q.push(e[i].v); } } } } } int main() { scanf("%d%d%d",&N,&ML,&MD); for (int i = 1; i < N; i++) { AddEdge(i+1,i,0); } for (int i = 1; i <= ML; i++) { scanf("%d%d%d",&AL,&BL,&DL); AddEdge(AL,BL,DL); } for (int i = 1; i <= MD; i++) { scanf("%d%d%d",&AD,&BD,&DD); AddEdge(BD,AD,-DD); } spfa(); if(flag) puts("-1"); else if(d[N] == INF) puts("-2"); else{ printf("%d\n",d[N]); } return 0; }