zoukankan      html  css  js  c++  java
  • UVa11248 Frequency Hopping 网络扩容

    传送


    题面:给定一个有向图,每条边均有一个容量。问是否存在一个从点(1)到点(n),流量为(c)的流。如果不存在,是否可以恰好修改一条边的容量,使得存在这样的流?


    首先如果最大流大于等于(C),那直接输出possible;
    否则要修改的一条边一定在最小割上,所以我们只要依次将每条最小割边的容量改成(C),再跑最大流检查即可。
    但这样最多要跑(m)次DInic,会TLE,所以这题的重点在于以下两点优化:

    1. 第一次求完最大流后把流量留着,以后都在这个基础上增广。
    2. 每次不用求最大流,大于等于(C)就可以返回。

    代码细节,还是有必要说一下的:

    1. 判断是否是最小割边:
    	for(int i = 1; i <= n; ++i) forE(j, i, v)	//访问每条边
    		if(dis[i] && !dis[v] && e[j].cap > 0)		//刚好在残量网络的断边上
    			ret.emplace_back(i, j);
    

     因为Dinic在bfs的时候只走流量未满的边,所以如果有的边满流量,且刚好位于残量网络能延伸的尽头,那么这些边就构成了最小割。
     2. 在第一次求完最大流的基础上增广:

    	for(int i = 0; i <= ecnt; ++i) e[i].cap -= e[i].flow;
    

     即改变每条边的流量,这样就能记住当前的残量网络了。
     3. 改每一条割边后不求最大流,大于等于(C)就返回:

    	for(int i = 0; i < (int)cuts.size(); ++i)
    	{
    		int x = cuts[i].S;				
    		e[x].cap = C;							//将流量修改为C
    		clearFlow();
    		if(flow + maxFlow(C - flow) >= C) ans.emplace_back(cuts[i].F, e[x].to);
    		e[x].cap = 0;							//改回来,因为是割边,所以必满流,新的容量就是0
    	}
    

     以及求最大流的部分:

    In int maxFlow(int lim)
    {
    	int flow = 0;
    	while(bfs())
    	{
    		memcpy(cur, head, sizeof(head));
    		flow += dfs(s, lim - flow);	
        //这我没搞懂,对于这道题改成dfs(s, INF)也能AC,但对于POJ1895这道题就不行
    		if(flow >= lim) return flow;
    	}
    	return flow;
    }
    

    以下是完整代码:
    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #include<cstdlib>
    #include<cctype>
    #include<vector>
    #include<queue>
    #include<assert.h>
    #include<ctime>
    using namespace std;
    #define enter puts("") 
    #define space putchar(' ')
    #define Mem(a, x) memset(a, x, sizeof(a))
    #define In inline
    #define forE(i, x, y) for(int i = head[x], y; ~i && (y = e[i].to); i = e[i].nxt)
    typedef long long ll;
    typedef double db;
    const int INF = 0x3f3f3f3f;
    const db eps = 1e-8;
    const int maxn = 105;
    const int maxe = 2e4 + 5;
    In ll read()
    {
    	ll ans = 0;
    	char ch = getchar(), las = ' ';
    	while(!isdigit(ch)) las = ch, ch = getchar();
    	while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
    	if(las == '-') ans = -ans;
    	return ans;
    }
    In void write(ll x)
    {
    	if(x < 0) x = -x, putchar('-');
    	if(x >= 10) write(x / 10);
    	putchar(x % 10 + '0');
    }
    
    int n, m, C, s, t;
    struct Edge
    {
    	int nxt, to, cap, flow;
    }e[maxe];
    int head[maxn], ecnt = -1;
    In void addEdge(int x, int y, int w)
    {
    	e[++ecnt] = (Edge){head[x], y, w, 0};
    	head[x] = ecnt;
    	e[++ecnt] = (Edge){head[y], x, 0, 0};
    	head[y] = ecnt;
    }
    
    int dis[maxn];
    In bool bfs()
    {
    	Mem(dis, 0), dis[s] = 1;
    	queue<int> q; q.push(s);
    	while(!q.empty())
    	{
    		int now = q.front(); q.pop();
    		for(int i = head[now], v; ~i; i = e[i].nxt)
    			if(e[i].cap > e[i].flow && !dis[v = e[i].to])
    				dis[v] = dis[now] + 1, q.push(v);
    	}
    	return dis[t];
    }
    int cur[maxn];
    In int dfs(int now, int res)
    {
    	if(now == t || res == 0) return res;
    	int flow = 0, f;
    	for(int& i = cur[now], v; ~i; i = e[i].nxt)
    	{
    		if(dis[v = e[i].to] == dis[now] + 1 && (f = dfs(v, min(res, e[i].cap - e[i].flow))) > 0)
    		{
    			e[i].flow += f, e[i ^ 1].flow -= f;
    			flow += f, res -= f;
    			if(res == 0) break;
    		}
    	}
    	return flow;
    }
    In int maxFlow(int lim)
    {
    	int flow = 0;
    	while(bfs())
    	{
    		memcpy(cur, head, sizeof(head));
    		flow += dfs(s, lim - flow);
    		if(flow >= lim) return flow;
    	}
    	return flow;
    }
    
    #define pr pair<int, int>
    #define mp make_pair
    #define F first			//起点 
    #define S second		//边所在的编号 
    In vector<pr> minCut()
    {
    	bfs();
    	vector<pr> ret;
    	for(int i = 1; i <= n; ++i) forE(j, i, v)
    		if(dis[i] && !dis[v] && e[j].cap > 0)
    			ret.emplace_back(i, j);
    	return ret;
    }
    
    In void clearFlow()
    {
    	for(int i = 0; i <= ecnt; ++i) e[i].flow = 0;
    }
    
    vector<pr> ans;
    In void solve(int flow)
    {
    	ans.clear();
    	vector<pr> cuts = minCut();
    	for(int i = 0; i <= ecnt; ++i) e[i].cap -= e[i].flow;
    	for(int i = 0; i < (int)cuts.size(); ++i)
    	{
    		int x = cuts[i].S;				//割边必满流 
    		e[x].cap = C;
    		clearFlow();
    		if(flow + maxFlow(C - flow) >= C) ans.emplace_back(cuts[i].F, e[x].to);
    		e[x].cap = 0;
    	}	
    }
    int main()
    {
    	int T = 0;
    	while(scanf("%d%d%d", &n, &m, &C) && (n | m | C))
    	{
    		Mem(head, -1), ecnt = -1;
    		s = 1, t = n;
    		for(int i = 1; i <= m; ++i)
    		{
    			int x = read(), y = read(), w = read();
    			addEdge(x, y, w);
    		}
    		printf("Case %d: ", ++T);
    		int flow = maxFlow(C);
    		if(flow >= C) {puts("possible"); continue;}
    		else solve(flow);
    		if(ans.empty()) puts("not possible");
    		else 
    		{
    			sort(ans.begin(), ans.end());
    			printf("possible option:");
    			for(int i = 0; i < (int)ans.size(); ++i) 
    				printf("(%d,%d)%c", ans[i].F, ans[i].S, i == (int)ans.size() - 1 ? '
    ' : ',');
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    [转] 学习React Native必看的几个开源项目
    [转] 「指尖上的魔法」
    [转] 为你的项目选择一个合适的开源协议
    [转] JavaScript中的属性:如何遍历属性
    [转] ReactNative Animated动画详解
    [转] Immutable 详解及 React 中实践
    [转] 在React Native中使用ART
    [转] 数字签名是什么?
    ipad itunes 恢复
    [转] react-native 之布局篇
  • 原文地址:https://www.cnblogs.com/mrclr/p/14901243.html
Copyright © 2011-2022 走看看