UVA-11478 Halum【二分】【差分約束】
阿新 • • 發佈:2018-11-04
題目大意
給你一個n個點,m條邊的有向圖
有一種操作把所有到達這個點的邊全部減小d,把所有從從這個點出發的邊加上d
問最後是否可以讓所有邊的邊權最小值最大
如果可以無限大,輸出\(Infinite\),如果不能讓所有邊權非負,輸出\(No\ solution\)
思路
最小值最大
就可以考慮二分了
然後發現對於任意一個點
所有在這個點上的操作是可以累加起來的,這樣我們就可以令\(c_u\)表示在u這個節點上的操作值的總和
那麼對於一條有向邊\((u,v)\),邊權是\(mid\le w_{u,v}+c_u-c_v\)
轉換成\(c_v-c_u\le w_{u,v}-mid\)
就把\(v\)到\(u\)連上長度是\(w_{u,v}-mid\)的邊
然後深搜spfa判斷負環就可以啦
為啥不廣搜?
廣搜1000ms深搜10ms你選哪一個?
在實際實現中其實發現c的正負沒有影響
所以咋推式子都行我寫程式碼和寫題解推的式子都不一樣
//Author: dream_maker #include<bits/stdc++.h> using namespace std; //---------------------------------------------- //typename typedef long long ll; //convenient for #define fu(a, b, c) for (int a = b; a <= c; ++a) #define fd(a, b, c) for (int a = b; a >= c; --a) #define fv(a, b) for (int a = 0; a < (signed)b.size(); ++a) //inf of different typename const int INF_of_int = 1e9; const ll INF_of_ll = 1e18; //fast read and write template <typename T> void Read(T &x) { bool w = 1;x = 0; char c = getchar(); while (!isdigit(c) && c != '-') c = getchar(); if (c == '-') w = 0, c = getchar(); while (isdigit(c)) { x = (x<<1) + (x<<3) + c -'0'; c = getchar(); } if (!w) x = -x; } template <typename T> void Write(T x) { if (x < 0) { putchar('-'); x = -x; } if (x > 9) Write(x / 10); putchar(x % 10 + '0'); } //---------------------------------------------- const int N = 1e5 + 10; struct Edge { int v, w, nxt; } E[N]; int fro[N], to[N], val[N]; int dis[N], inq[N]; int head[N], tot, n, m; void add(int u, int v, int w) { E[++tot] = (Edge) {v, w, head[u]}; head[u] = tot; } void init() { fu(i, 1, n) dis[i] = INF_of_int; fu(i, 1, n) head[i] = inq[i] = 0; tot = 0; } bool spfa(int u) { inq[u] = 1; for (int i = head[u]; i; i = E[i].nxt) { int v = E[i].v; if (dis[v] > dis[u] + E[i].w) { dis[v] = dis[u] + E[i].w; if (inq[v] || (!inq[v] && !spfa(v))) return 0; } } inq[u] = 0; return 1; } /* bool spfa() { static queue<int> q; fu(i, 1, n) inq[i] = 1, q.push(i); while (q.size()) { int u = q.front(); q.pop(); inq[u] = 0; for (int i = head[u]; i; i = E[i].nxt) { int v = E[i].v; if (dis[v] > dis[u] + E[i].w) { dis[v] = dis[u] + E[i].w; if (!inq[v]) { if (++vis[v] >= n) return 0; else inq[v] = 1, q.push(v); } } } } return 1; } */ bool check(int key) { init(); fu(i, 1, m) add(to[i], fro[i], val[i] - key); fu(i, 1, n) if (!spfa(i)) return 0; return 1; } void work() { int l = 1, r = 1; fu(i, 1, m) { Read(fro[i]), Read(to[i]), Read(val[i]); r = max(r, val[i]); } if (check(r)) {printf("Infinite\n");} else if (!check(l)) {printf("No Solution\n");} else { int res = 1; while (l <= r) { int mid = (l + r) >> 1; if (check(mid)) l = mid + 1, res = mid; else r = mid - 1; } Write(res), putchar('\n'); } } int main() { #ifdef dream_maker freopen("input.txt", "r", stdin); freopen("output.txt", "w", stdout); #endif while (scanf("%d %d", &n, &m) != EOF) work(); }