zoukankan      html  css  js  c++  java
  • POJ2175 Evacuation Plan

    嘟嘟嘟


    题目大意:给一个费用流的残量网络,判断是不是最优解。如果不是,输出比当前解更优的任意一种方案。


    刚开始以为是水题:建完图后跑费用流,并记录选取方案,最后输出。
    然而这样会(TLE)
    所以我还是看了题解。
    原来用了费用流的一条性质:当前流是最小费用流 (<=>)残量网络中没有负圈。
    所以做法就是建好残量网络,然后跑(spfa)找负环,然后修改环中的边的流量。
    具体做法:
    1.根据题目可知,从源点向每一栋楼房的边一定都流满了,因此可以不建。而且这也告诉我们要从汇点开始跑。
    2.找负环的时候,要保证每一条边的残量都是正的,然后以费用为边权找负环。
    3.找到负环退出的时候当前点可能不是负环。解决方法是沿着记录的路径往回跑,并标记,如果遇到一个已经被标记的点,那么这个点肯定在负环里。那么从这个点再开始找路径,直到又回到这个点,这期间的点一定都在负环里。
    4.因为只用输出比当前更优的一种方案,因此把负环上的边流量加1即可。
    5.这题用邻接矩阵是最方便的。因为按题中要求,几乎每两个点之间都会连边,所以几乎没有浪费空间,而且在后面的修改和统计答案的时候也非常方便。

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #include<cstdlib>
    #include<cctype>
    #include<vector>
    #include<stack>
    #include<queue>
    using namespace std;
    #define enter puts("") 
    #define space putchar(' ')
    #define Mem(a, x) memset(a, x, sizeof(a))
    #define rg register
    typedef long long ll;
    typedef double db;
    const int INF = 0x3f3f3f3f;
    const db eps = 1e-8;
    const int maxn = 105;
    inline ll read()
    {
      ll ans = 0;
      char ch = getchar(), last = ' ';
      while(!isdigit(ch)) last = ch, ch = getchar();
      while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
      if(last == '-') ans = -ans;
      return ans;
    }
    inline void write(ll x)
    {
      if(x < 0) x = -x, putchar('-');
      if(x >= 10) write(x / 10);
      putchar(x % 10 + '0');
    }
    
    int n, m, s, t;
    struct Buil
    {
      int x, y, num;
    }a[maxn], b[maxn];
    
    int G[maxn << 1][maxn << 1], c[maxn << 1][maxn << 1], sum[maxn];
    
    bool in[maxn << 1];
    int dis[maxn << 1], du[maxn << 1], pre[maxn << 1];
    int spfa()
    {
    	Mem(in, 0); Mem(dis, 0x3f); Mem(du, 0);
    	queue<int> q; q.push(t);
    	in[t] = 1; dis[t] = 0; du[t] = 1;
      	while(!q.empty())
        {
    		int now = q.front(); q.pop(); in[now] = 0;
    		for(int i = 0; i <= t; ++i)
    		{
    			if(G[now][i] && dis[i] > dis[now] + c[now][i])
    		    {
    		    	dis[i] = dis[now] + c[now][i];
    		      	pre[i] = now;
    		      	if(!in[i]) 
    				{
    					in[i] = 1, q.push(i);
    					if(++du[i] > t) return i; 	
    				}
    		    }
    		}
        }
        return -1;
    }
    
    int Dis(Buil a, Buil b)
    {
    	return abs(a.x - b.x) + abs(a.y - b.y) + 1;
    }
    
    int main()
    {
    	n = read(); m = read(); s = 0; t = n + m + 1;
    	for(int i = 1; i <= n; ++i) a[i].x = read(), a[i].y = read(), a[i].num = read();
    	for(int i = 1; i <= m; ++i) b[i].x = read(), b[i].y = read(), b[i].num = read();
    	for(int i = 1; i <= n; ++i)
    	{
    		for(int j = 1; j <= m; ++j)
    		{
    			c[i][j + n] = Dis(a[i], b[j]);
    			c[j + n][i] = -c[i][j + n];
    			G[i][j + n] = a[i].num;
    		}
    	}
    	for(int i = 1; i <= n; ++i)
    		for(int j = 1; j <= m; ++j)
    		{
    			int d = read();
    			G[i][j + n] -= d;
    			G[j + n][i] = d;
    			sum[j] += d;
    		}
    	for(int i = 1; i <= m; ++i)
    	{
    		G[i + n][t] = b[i].num - sum[i];
    		G[t][i + n] = sum[i];
    	}
    	int ans = spfa();
    	if(ans == -1) puts("OPTIMAL");
    	else
    	{
    		puts("SUBOPTIMAL");
    		Mem(in, 0);
    		int x = ans;
    		while(!in[x])
    		{
    			in[x] = 1;
    			x = pre[x];
    		}
    		ans = x;
    		do
    		{
    			G[pre[x]][x]--;
    			G[x][pre[x]]++;
    			x = pre[x];
    		}while(x != ans);
    		for(int i = 1; i <= n; ++i)
    		{
    			for(int j = 1; j <= m; ++j) write(G[j + n][i]), space;
    			enter;
    		}
    	}
    	return 0;
    }
    

    再发一个用费用流写的$TLE$的代码的关键部分: 建图: ```c++ for(int i = 1; i <= n; ++i) { a[i].x = read(); a[i].y = read(); a[i].num = read(); addEdge(s, i, a[i].num, 0); } for(int i = 1; i <= m; ++i) { b[i].x = read(); b[i].y = read(); b[i].num = read(); for(int j = 1; j <= n; ++j) addEdge(j, i + n, INF, qdis(a[j], b[i])); addEdge(i + n, t, b[i].num, 0); } ``` 更新: ```c++ void update() { int x = t; while(x != s) { int i = pre[x]; e[i].cap -= flow[t]; e[i ^ 1].cap += flow[t]; Ans[e[i].from][e[i].to] += flow[t]; Ans[e[i].to][e[i].from] -= flow[t]; x = e[i].from; } minCost += flow[t] * dis[t]; } ```
  • 相关阅读:
    docker 之 docker-compose 初探
    docker 之 .net core 镜像制作
    docker 之 registry私有仓库(harbor)
    ASP.NET Core 学习笔记(认证授权)
    ASP.NET Core 学习笔记(http请求处理)
    ASP.NET Core 学习笔记(依赖注入)
    Linux基础编程之网络编程TCP实例
    功能包和CMakeLists.txt
    ROS的主节点(名称服务器)---roscore
    关于ros开发
  • 原文地址:https://www.cnblogs.com/mrclr/p/10014089.html
Copyright © 2011-2022 走看看