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;
    }
    
  • 相关阅读:
    Java异常处理和设计
    一次qps测试实践
    Alternate Task UVA
    Just Another Problem UVA
    Lattice Point or Not UVA
    Play with Floor and Ceil UVA
    Exploring Pyramids UVALive
    Cheerleaders UVA
    Triangle Counting UVA
    Square Numbers UVA
  • 原文地址:https://www.cnblogs.com/mrclr/p/14901243.html
Copyright © 2011-2022 走看看