題目連結:點選打開連結
題意:
給定n個點m條限制。
下面輸出 u v x 表示:
dis[u] - dis[v] >= x
然後建圖就是 u->v 邊權為-x
輸出一個解滿足 -10000<= dis[i] <= 10000。
若有多解輸出一個 dis[n] - dis[1] 最小的解。
思路:
正圖求個最大解,反圖求個最小解。
對于一個點的 最大解<最小解,則差分限制無解。
題目要求dis[n]-dis[1]最小,那就令dis[n]為其最小解,dis[1]為其最大解,再spfa一遍就好。
注意:這裡所說的最大解最小解是需要确定一個變量的。則這個變量就是(解集中max(dis[i]) = inf)
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>
#include <math.h>
#include <map>
#include <queue>
using namespace std;
#define N 10010
#define M 100010
#define inf 10000
struct Edge{
int to, dis, nex;
};
int inq[N], Tim[N];
int n, m;
bool spfa(int head[], Edge edge[], int dis[]){
queue<int> q;
for(int i = 1; i <= n; i++) Tim[i] = 0, inq[i] = 1, q.push(i);
while(!q.empty()){
int u = q.front(); q.pop(); inq[u] = 0;
for(int i = head[u]; ~i; i = edge[i].nex){
int v = edge[i].to;
if(dis[v] > dis[u] + edge[i].dis) {
dis[v] = dis[u]+edge[i].dis;
if(!inq[v]) {
Tim[v]++;
if(Tim[v] > n) return false;
inq[v] = 1;
q.push(v);
}
}
}
}
return true;
}
Edge edge[M], Fedge[M];
int head[N], edgenum, fan[N];
void init(){memset(head, -1, sizeof head); memset(fan, -1, sizeof fan); edgenum = 0; }
void add(int u, int v, int d){
Edge E = {v, d, head[u]}; edge[edgenum] = E; head[u] = edgenum;
Edge E2 = {u, d, fan[v]}; Fedge[edgenum] = E2; fan[v] = edgenum++;
}
int disg[N], disr[N];
int solve(){
init();
int u, v, d;
while(m--){
scanf("%d %d %d", &u, &v, &d);
add(u, v, -d);
}
for(int i = 1; i <= n; i++) disg[i] = inf;
if(spfa(head, edge, disg)==false) return -1;
for(int i = 1; i <= n; i++) disr[i] = inf;
if(spfa(fan, Fedge, disr)==false) return -1;
for(int i = 1; i <= n; i++)
if(disg[i] < -disr[i])
return -1;
disg[n] = -disr[n];
spfa(head, edge, disg);
for(int i = 1; i <= n; i++)printf("%d%c", disg[i], i==n?'\n':' ');
return 0;
}
int main(){
while(cin>>n>>m)
if(solve()==-1)puts("-1");
return 0;
}
/*
3 3
1 2 1
2 1 1
3 1 2
3 3
1 2 1
2 1 -1
3 1 2
3 3
1 2 1
2 1 -1
1 3 2
*/