題意:ios
n個房子m條路徑邊的無向圖,每一個房子能夠最終容納b我的,初始有a我的,中途超過能夠超過b我的,每條邊有一個長度,通過一條邊的時間花費爲邊的長度。求全部人都進入房子的最小時間。若是不能容納全部人,輸出最少多少人沒法進入房子。git
分析:spa
注意圖不必定聯通!!!code
首先Floyd一遍,求出任意兩點之間的距離,二分一個答案,而後拆點建二分圖,S想每一個點連a的容量,另外一個點向T連b的容量,對於兩個點a,b,若是dis[a][b]<=二分的這個數,就加入一條左邊到右邊的邊,容量爲inf。滿流便可。blog
代碼:get
#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #include<cctype> #include<cmath> #include<set> #include<map> #include<vector> #include<queue> #include<bitset> #define fore(i, u, v) for (int i = head[u], v = e[i].to; i; i = e[i].nxt, v = e[i].to) using namespace std; typedef long long LL; inline int read() { int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f; } const int N = 5005, INF = 1e9; struct Edge { int to, nxt, cap; } e[100005]; int head[N], q[50005], a[N], b[N], dis[N], cur[N]; int En = 1, S, T, n; LL d[305][305], Sum; inline void add_edge(int u,int v,int f) { ++En; e[En].to = v, e[En].nxt = head[u], e[En].cap = f; head[u] = En; ++En; e[En].to = u, e[En].nxt = head[v], e[En].cap = 0; head[v] = En; } bool bfs() { for (int i = 0; i <= T; ++i) dis[i] = -1, cur[i] = head[i]; int L = 1, R = 0; q[++R] = S; dis[S] = 0; while (L <= R) { int u = q[L ++]; fore(i, u, v) if (dis[v] == -1 && e[i].cap > 0) { dis[v] = dis[u] + 1; if (v == T) return true; q[++R] = v; } } return false; } int dfs(int u,int flow) { if (u == T) return flow; int used = 0, tmp; for (int &i = cur[u]; i; i = e[i].nxt) { int v = e[i].to; if (dis[v] == dis[u] + 1 && e[i].cap > 0) { tmp = dfs(v, min(e[i].cap, flow - used)); if (tmp > 0) { e[i].cap -= tmp, e[i ^ 1].cap += tmp; used += tmp; if (used == flow) break; } } } if (flow != used) dis[u] = -1; return used; } bool dinic(LL x, bool flag) { S = 0, T = n + n + 1, En = 1; memset(head, 0, sizeof(head)); for (int i = 1; i <= n; ++i) add_edge(S, i, a[i]), add_edge(i + n, T, b[i]); for (int i = 1; i <= n; ++i) for (int j = 1; j <= n; ++j) if (d[i][j] <= x) add_edge(i, j + n, INF); LL ans = 0; while (bfs()) ans += dfs(S, INF); if (flag && ans != Sum) { cout << "NO\n" << Sum - ans; exit(0); } return ans == Sum; } void solve(int m) { for (int i = 1; i <= n; ++i) Sum += a[i]; // memset(d, 0x3f, sizeof(d)); for (int i = 1; i <= n; ++i) for (int j = 1; j <= n; ++j) d[i][j] = 1e18; for (int i = 1; i <= n; ++i) d[i][i] = 0; for (int i = 1; i <= m; ++i) { int u = read(), v = read(), w = read(); d[u][v] = min(d[u][v], (LL)w); d[v][u] = min(d[v][u], (LL)w); } for (int k = 1; k <= n; ++k) for (int i = 1; i <= n; ++i) for (int j = 1; j <= n; ++j) d[i][j] = min(d[i][j], d[i][k] + d[k][j]); LL L = 1e18, R = 0, ans = 0; for (int i = 1; i <= n; ++i) for (int j = 1; j <= n; ++j) if (d[i][j] != 1e18) L = min(L, d[i][j]), R = max(R, d[i][j]); // 注意要有dis[i][j]!=1e18??? dinic(R, 1); while (L <= R) { LL mid = (L + R) >> 1; if (dinic(mid, 0)) R = mid - 1, ans = mid; else L = mid + 1; } cout << "YES\n" << ans << "\n"; } int main() { n = read();int m = read(); for (int i = 1; i <= n; ++i) a[i] = read(), b[i] = read(); solve(m); return 0; }