POJ 2175 最小费用最大流之消圈 根据已有流量建立残留网络

本文主要是介绍POJ 2175 最小费用最大流之消圈 根据已有流量建立残留网络,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

这道题看似是建图十分简单,实则用裸的最小费用最大流必然会超时,用zkw费用流也会超时。

所以必须看清题意,题目要求只要比当前方案好就行,没说要最好。

那么根据定理,一个费用流是最小费用流的充要条件是这个费用流的残量网络没有负费用圈。对于这个定理,如果不明白可以画一画。

那么对本题来讲,只需要消一次圈就可以找到一个比当前方案好的方案,当然前提是网络中有负圈得情况下。

此时只需沿着负费用圈把各边流量增加1(这条负费用圈上有逆边,逆边流量加1相当于其对应的正边流量减1),增流之后残量网络对应的方案肯定是一个更优方案

那么怎么根据已有的流量建立残留网络呢。

实际上就是一个逆向思考的过程。
 所有的建筑物i和避难所j,连接ij,边权为正的距离。因为i,j之间容量肯定无穷
 如果原方案i到j有人,连接ji,边权为负的距离。如果i到j有流量过去,那么j到i的容量就大于0,并且花费是负的,因为这是由最小费用最大流的建的边所决定的。
 如果j避难所的人数大于0,连接汇点和j,边权0.
如果j避难所没有满,连接j和汇点,边权0.

#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <cstdio>
#include <cmath>
#include <queue>
#include <map>
#include <set>
#define eps 1e-5
#define MAXN 555
#define MAXM 55555
#define INF 100000007
using namespace std;
struct P
{int x, y, w;
}a[MAXN], b[MAXN];
struct EDGE
{int v, w, next;
}edge[MAXM];
int head[MAXN], e;
int d[MAXN], vis[MAXN], pre[MAXN], cnt[MAXN];
int que[MAXN * MAXN];
int nt, n, m;
int ans[MAXN][MAXN], g[MAXN][MAXN], sum[MAXN];
void init()
{e = 0;memset(head, -1, sizeof(head));memset(cnt, 0, sizeof(cnt));memset(pre, -1, sizeof(pre));
}
void add(int u, int v, int w)
{edge[e].v = v;edge[e].w = w;edge[e].next = head[u];head[u] = e++;
}
int spfa(int src)
{for(int i = 0; i <= n; i++) d[i] = INF, vis[i] = 0;vis[src] = 1;int h = 0, t = 0;que[t++] = src;d[src] = 0;cnt[src]++;while(h < t){int u = que[h++];vis[u] = 0;for(int i = head[u]; i != -1; i = edge[i].next){int v = edge[i].v;int w = edge[i].w;if(d[u] + w < d[v]){d[v] = d[u] + w;pre[v] = u;if(!vis[v]){vis[v] = 1;que[t++] = v;if(++cnt[v] > n) return v;}}}}return -1;
}
int main()
{scanf("%d%d", &nt, &m);init();for(int i = 0; i < nt; i++) scanf("%d%d%d", &a[i].x, &a[i].y, &a[i].w);for(int i = 0; i < m; i++) scanf("%d%d%d", &b[i].x, &b[i].y, &b[i].w);n = nt + m;for(int i = 0; i < nt; i++)for(int j = 0; j < m; j++){g[i][j] = abs(a[i].x - b[j].x) + abs(a[i].y - b[j].y) + 1;add(i, j + nt, g[i][j]);}for(int i = 0; i < nt; i++)for(int j = 0; j < m; j++){scanf("%d", &ans[i][j]);if(ans[i][j]){add(j + nt, i, -g[i][j]);sum[j] += ans[i][j];}}for(int i = 0; i < m; i++){if(sum[i] < b[i].w) add(i + nt, nt + m, 0);if(sum[i] > 0) add(nt + m, i + nt, 0);}int u = spfa(nt + m);if(u == -1) printf("OPTIMAL\n");else{printf("SUBOPTIMAL\n");memset(vis, 0, sizeof(vis));int v = u;while(!vis[v]){vis[v] = 1;v = pre[v];}u = v;do{if(pre[v] < nt && v >= nt) ans[pre[v]][v - nt]++;if(v < nt && pre[v] >= nt) ans[v][pre[v] - nt]--;v = pre[v];}while(v != u);for(int i = 0; i < nt; i++)for(int j = 0; j < m; j++){if(j == m - 1) printf("%d\n", ans[i][j]);else printf("%d ", ans[i][j]);}}return 0;
}


这篇关于POJ 2175 最小费用最大流之消圈 根据已有流量建立残留网络的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/368901

相关文章

使用zabbix进行监控网络设备流量

《使用zabbix进行监控网络设备流量》这篇文章主要为大家详细介绍了如何使用zabbix进行监控网络设备流量,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录安装zabbix配置ENSP环境配置zabbix实行监控交换机测试一台liunx服务器,这里使用的为Ubuntu22.04(

SSID究竟是什么? WiFi网络名称及工作方式解析

《SSID究竟是什么?WiFi网络名称及工作方式解析》SID可以看作是无线网络的名称,类似于有线网络中的网络名称或者路由器的名称,在无线网络中,设备通过SSID来识别和连接到特定的无线网络... 当提到 Wi-Fi 网络时,就避不开「SSID」这个术语。简单来说,SSID 就是 Wi-Fi 网络的名称。比如

Java实现任务管理器性能网络监控数据的方法详解

《Java实现任务管理器性能网络监控数据的方法详解》在现代操作系统中,任务管理器是一个非常重要的工具,用于监控和管理计算机的运行状态,包括CPU使用率、内存占用等,对于开发者和系统管理员来说,了解这些... 目录引言一、背景知识二、准备工作1. Maven依赖2. Gradle依赖三、代码实现四、代码详解五

如何提高Redis服务器的最大打开文件数限制

《如何提高Redis服务器的最大打开文件数限制》文章讨论了如何提高Redis服务器的最大打开文件数限制,以支持高并发服务,本文给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧... 目录如何提高Redis服务器的最大打开文件数限制问题诊断解决步骤1. 修改系统级别的限制2. 为Redis进程特别设置限制

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor

poj 3974 and hdu 3068 最长回文串的O(n)解法(Manacher算法)

求一段字符串中的最长回文串。 因为数据量比较大,用原来的O(n^2)会爆。 小白上的O(n^2)解法代码:TLE啦~ #include<stdio.h>#include<string.h>const int Maxn = 1000000;char s[Maxn];int main(){char e[] = {"END"};while(scanf("%s", s) != EO

hdu 2602 and poj 3624(01背包)

01背包的模板题。 hdu2602代码: #include<stdio.h>#include<string.h>const int MaxN = 1001;int max(int a, int b){return a > b ? a : b;}int w[MaxN];int v[MaxN];int dp[MaxN];int main(){int T;int N, V;s

poj 1511 Invitation Cards(spfa最短路)

题意是给你点与点之间的距离,求来回到点1的最短路中的边权和。 因为边很大,不能用原来的dijkstra什么的,所以用spfa来做。并且注意要用long long int 来存储。 稍微改了一下学长的模板。 stack stl 实现代码: #include<stdio.h>#include<stack>using namespace std;const int M

poj 3259 uva 558 Wormholes(bellman最短路负权回路判断)

poj 3259: 题意:John的农场里n块地,m条路连接两块地,w个虫洞,虫洞是一条单向路,不但会把你传送到目的地,而且时间会倒退Ts。 任务是求你会不会在从某块地出发后又回来,看到了离开之前的自己。 判断树中是否存在负权回路就ok了。 bellman代码: #include<stdio.h>const int MaxN = 501;//农场数const int

poj 1258 Agri-Net(最小生成树模板代码)

感觉用这题来当模板更适合。 题意就是给你邻接矩阵求最小生成树啦。~ prim代码:效率很高。172k...0ms。 #include<stdio.h>#include<algorithm>using namespace std;const int MaxN = 101;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int n