题目链接:http://acm.uestc.edu.cn/#/problem/show/1638
题意:
给定n个点(点权未知)和m条信息:u的权值>=v的权值+w
求点权的极小解和极大解(无解则输出-1)
极小解即每个点的点权可能的最小值
极大解即每个点的点权可能的最大值
数据范围:
1<=n<=100000
1<=m<=1000000
0<=w<=100
点权为0到100之间的整数
题解:
差分约束。
求最大值,跑最短路,建一条从v到u权值为w的边。
求最小值,跑最长路,建一条从u到v权值为-w的边。
#include <bits/stdc++.h> using namespace std; const int maxn = 1e5+7; const int maxm = 1e6+7; struct edge{ int v, w, next; edge(int v=0, int w=0, int next=0):v(v),w(w),next(next){} }E1[2*maxm], E2[2*maxm]; int head1[maxn], head2[maxn], cnt1, cnt2; int n, m, cnt[maxn], inq[maxn], mx[maxn], mi[maxn], Q[maxn]; void init(){ memset(head1, -1, sizeof(head1)); memset(head2, -1, sizeof(head2)); cnt1 = cnt2 = 0; } void add(int u, int v, int w, int op) { if(op&1){ E1[cnt1]=edge(v,w,head1[u]), head1[u]=cnt1++; } else{ E2[cnt2]=edge(v,w,head2[u]), head2[u]=cnt2++; } } bool spfa1(){ int top = 0; memset(mi, -1, sizeof(mi)); mi[0] = 0; cnt[0] = 1; inq[0] = 1; Q[top++] = 0; while(top){ int u = Q[--top]; inq[u] = 0; for(int i = head1[u]; ~i; i = E1[i].next){ int v = E1[i].v, w = E1[i].w; if(mi[v] < mi[u] + w){ mi[v] = mi[u] + w; if(inq[v]) continue; if(cnt[v] > n) return 0; cnt[v]++; inq[v] = 1; Q[top++] = v; } } } return 1; } bool spfa2(){ int top = 0; memset(mx, 0x3f, sizeof(mx)); memset(inq, 0, sizeof(inq)); memset(cnt, 0, sizeof(cnt)); mx[0] = 100; cnt[0] = 1; inq[0] = 1; Q[top++] = 0; while(top){ int u = Q[--top]; inq[u] = 0; for(int i = head2[u]; ~i; i=E2[i].next){ int v = E2[i].v, w = E2[i].w; if(mx[v] > mx[u] + w){ mx[v] = mx[u] + w; if(inq[v]) continue; if(cnt[v] > n) return 0; cnt[v]++; inq[v] = 1; Q[top++] = v; } } } for(int i=1; i<=n; i++){ if(min(mi[i],mx[i])<0 || max(mi[i],mx[i])>100) return 0; } return 1; } int main() { init(); scanf("%d %d", &n,&m); for(int i = 1; i <= m; i++){ int u, v, w; scanf("%d %d %d", &u,&v,&w); add(v, u, w, 1); add(u, v, -w, 2); } for(int i = 1; i <= n; i++){ add(0, i, 0, 1); add(0, i, 0, 2); } if(spfa1()&&spfa2()) { for(int i = 1; i <= n; i++){ printf("%d %d\n", mi[i], mx[i]); } } else{ puts("-1"); } return 0; }