zoukankan      html  css  js  c++  java
  • Gym 102007I 二分 网络流

    题意:给你一张图,每个城市有一些人,有不超过10个城市有避难所,避难所有容量上限,问最快多久可以让所有人进入避难所?

    思路:二分时间,对于每个时间跑一遍最大流,判断最大流是不是人数即可。我们还需要用二进制优化一下,对于每个二分的时间,我们需要预处理出某个城市可以到达哪些避难所,表示成状态。如果在当前时间下两个城市可以到达的避难所是一样的,我们就可以用一个状态表示,这样把点数限制在了1e3级别。

    代码:

    #include <bits/stdc++.h>
    #include <ext/pb_ds/priority_queue.hpp>
    #define LL long long
    #define pLi pair<LL ,int>
    #define pii pair<int, int>
    #define INF 0x3f3f3f3f3f3f3f3f
    using namespace std;
    using namespace __gnu_pbds;
    const int maxn = 200100;
    const int maxm = 501000;
    typedef __gnu_pbds::priority_queue<pLi, greater<pLi>, pairing_heap_tag> Heap;
    int heade[maxn],
     Nexte[maxm], vere[maxm], edgee[maxm], tote;
    LL dis[10][maxn];
    pair<int, int> b[20];
    int n, k;
    int a[maxn];
    LL re[maxn * 10];
    void adde(int x, int y, int z) {
    	vere[++tote] = y;
    	edgee[tote] = z;
    	Nexte[tote] = heade[x];
    	heade[x] = tote;
    }
    Heap q;
    int s, t;
    void dijkstra(int s, int flag) {
    	memset(dis[flag], 0x3f, sizeof(dis[flag]));
    	Heap::point_iterator id[maxn];
    	dis[flag][s] = 0;
    	id[s] = q.push(make_pair(dis[flag][s], s));
    	while(!q.empty()) {
    		int x = q.top().second;
    		q.pop();
    		for (int i = heade[x]; i; i = Nexte[i]) {
    			int y = vere[i], z = edgee[i];
    			if(dis[flag][y] > dis[flag][x] + z) {
    				dis[flag][y] = dis[flag][x] + z;
    				if(id[y] != 0) q.modify(id[y], make_pair(dis[flag][y], y));
    				else id[y] = q.push(make_pair(dis[flag][y], y));
    			}
    		}
    	}
    }
    int head[maxn], Next[maxn * 25], ver[maxn * 25], tot;
    LL edge[maxn * 25];
    int deep[maxn];
    void add(int x, int y, LL z) {
    	ver[++tot] = y, edge[tot] = z, Next[tot] = head[x], head[x] = tot;
    	ver[++tot] = x, edge[tot] = 0, Next[tot] = head[y], head[y] = tot;
    }
    queue<int> Q;
    bool bfs(LL limit) {
    	memset(deep, 0, sizeof(deep));
    	while(Q.size())Q.pop();
    	Q.push(s); deep[s] = 1;
    	while(Q.size()) {
    		int x = Q.front();Q.pop();
    		for (int i = head[x]; i; i = Next[i]) {
    			if(edge[i] && !deep[ver[i]]) {
    				Q.push(ver[i]);
    				deep[ver[i]] = deep[x] + 1;
    				if(ver[i] == t) return 1;
    			}
    		}
    	}
    	return 0;
    }
    LL dinic(int x, LL flow) {
    	if(x == t) return flow;
    	LL rest = flow, k;
    	for (int i = head[x]; i && rest; i = Next[i]) {
    		if(edge[i] && deep[ver[i]] == deep[x] + 1) {
    			k = dinic(ver[i], min(rest, edge[i]));
    			if(!k) deep[ver[i]] = 0;
    			edge[i] -= k;
    			edge[i ^ 1] += k;
    			rest -= k;
    		}
    	}
    	return flow - rest;
    }
    LL solve(int now) {
    	tot = 1;
    	LL maxflow = 0;
    //	memset(head, 0, sizeof(head));
    	memset(head, 0, sizeof(int) * (n + 1));
    	for (int i = 0; i < k; i++)
    		head[b[i].first + n] = 0;
    	head[t] = 0;
    	for (int i = 1; i <= n; i++) {
    		if(a[i])
    			add(s, i, a[i]);
    	}
    	LL tmp;
    	for (int i = 1; i <= n; i++) {
    		tmp = 0;
    		if(a[i] == 0) continue;
    		for (int j = 0; j < k; j++) {
    			if(dis[j][i] >= re[now]) continue;
    			tmp += b[j].second;
    			add(i, b[j].first + n, INF);
    		}
    		if(tmp < a[i]) {
    			return 0;
    		}
    	}
    	for (int i = 0; i < k; i++)
    		add(b[i].first + n, t, b[i].second);
    	LL flow;
    	while(bfs(re[now])) {
    		while(flow = dinic(s, INF)) maxflow += flow;
    	}
    	return maxflow;
    }
    int main() {
    	LL cnt = 0;
    	s = 0, t = 2 * n + 20;
    	int m, x, y, z;
    	scanf("%d%d%d", &n, &m, &k);
    	for (int i = 1; i <= n; i++)  {
    		scanf("%d", &a[i]);
    		cnt += a[i];
    	}
    	for (int i = 1; i <= m; i++) {
    		scanf("%d%d%d", &x, &y, &z);
    		adde(x, y, z);
    		adde(y, x, z); 
    	}
    	for (int i = 0; i < k; i++) {
    		scanf("%d%d", &b[i].first, &b[i].second);
    		dijkstra(b[i].first, i);
    	}
    	for (int i = 0; i < k; i++)
    		for (int j = 1; j <= n; j++) {
    			re[++tot] = dis[i][j];
    		}
    	sort(re + 1, re + 1 + tot);
    	int sz = unique(re + 1, re + 1 + tot) - (re + 1);
    	int l = 1, r = sz + 1;
    	re[sz + 1] = INF;
    	while(l < r) {
    		int mid = (l + r) >> 1;
    		if(solve(mid) == cnt) r = mid;
    		else l = mid + 1;
    	}
    	printf("%lld
    ", re[l - 1]);
    }
    

      

  • 相关阅读:
    完美世界经典版本881外挂
    ShowModal 动态创建窗体和释放窗体
    HTML 颜色代码大全
    padding margin border 的四值顺序
    三 C# Socket通信 窗体控件与多线程
    Java解压缩Zip 文件
    八 C# Socket通信 通信协议设计
    CSS+DIV实现鼠标经过背景变色
    七 C# Socket通信 阻塞性线程的快速终止
    二 C# Socket通信模式
  • 原文地址:https://www.cnblogs.com/pkgunboat/p/10871248.html
Copyright © 2011-2022 走看看