ZOJ1994有源汇上下界可行流
http://fastvj.rainng.com/contest/236779#problem/G
Description:
n 行 m 列
给你行和 与 列和
然后有Q个限制,表示特定单元格元素大小的范围,最后问你可行的矩阵值
Solution:
有源汇上下界最大流问题,初始源点 连 行和流量是该行对应得行和,然后列连初始汇点,容量为列的列和,详细的限制,对应于行列之间,因为我最后要输出一个矩阵,所以n * m每一条边都要链接最后,手动连一条 t s inf的边,变成无源汇有上下界可行流问题,然后拆边,把对应边的流量,放到数组里,输出就好啦
Code:
前面比较基础的Dinic,数据操作函数,加边操作
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#define inf (1 << 28)
using namespace std;
const int maxn = 25;
const int maxm = 210;
const int mn = 505;
const int mm = 440020;
struct node{
int to,val,pre,lid;
}e[mm];
int id[mn],cnt=0; int cur[mn];
int flor[mn]; int upflow[mn];
int lowf[maxm][maxn];
int upf[maxm][maxn];
int out[maxm][maxn];
void init()
{
memset(id,-1,sizeof(id));
memset(upflow,0,sizeof(upflow));
cnt = 0;
}
void add(int from,int to,int val,int lid)
{
e[cnt].to = to;
e[cnt].val = val;
e[cnt].lid = lid;
e[cnt].pre = id[from];
id[from] = cnt++;
swap(from,to);
e[cnt].to = to;
e[cnt].val = 0;
e[cnt].lid = lid;
e[cnt].pre = id[from];
id[from] = cnt++;
}
void addflow(int from,int to,int low,int up,int lid)
{
upflow[from] -= low;
upflow[to] += low;
add(from,to,up-low,lid);
}
bool bfs(int s,int t)
{
memset(flor,0,sizeof(flor));
flor[s] = 1;
queue<int> q;
while(q.size())q.pop(); q.push(s);
while(q.size())
{
int now = q.front();
q.pop(); for(int i = id[now];~i;i = e[i].pre)
{
int to = e[i].to;
int val = e[i].val;
if(val > 0 && flor[to] == 0)
{
flor[to] = flor[now] + 1;
q.push(to);
if(to == t)
return true;
}
}
}
return false;
}
int dfs(int s,int t,int value)
{
if(s == t || value == 0)return value; int ret = value,a; for(int &i = cur[s];~i;i = e[i].pre)
{
int val = e[i].val;
int to = e[i].to;
if(flor[to] == flor[s] + 1 && (a = dfs(to,t,min(ret,val))))
{
e[i].val -= a;
e[i^1].val += a;
ret -= a;
if(ret == 0)break;
}
}
if(ret == value)flor[s] = 0;
return value - ret;
} int Dinic(int s,int t)
{
int ret = 0;
while(bfs(s,t))
{
memcpy(cur,id,sizeof(id));
ret += dfs(s,t,inf);
}
return ret;
} void addlimit(int i,int j,char op,int lim)
{
if(op == '=')
{
upf[i][j] = lowf[i][j] = lim;
}
else if(op == '>')
{
lowf[i][j] = max(lowf[i][j],lim+1);
}
else
{
upf[i][j] = min(upf[i][j],lim-1);
}
}
然后根据输入一点点的加边,这是行和和列和对应的边
scanf("%d%d",&n,&m);
s = 0;
t = n + m + 1;
ss = t + 1;
tt = ss + 1;
int lsum;
for(int i = 1;i <= n;++i)
{
scanf("%d",&lsum);
addflow(s,i,lsum,lsum,0);
}
for(int i = 1;i <= m;++i)
{
scanf("%d",&lsum);
addflow(n + i,t,lsum,lsum,0);
}
int limitnum;
然后根据题目中给出的限制条件,填充上下界数组
scanf("%d",&limitnum);
for(int i = 1;i <= n;++i)
{
for(int j = 1;j <= m;++j)
{
lowf[i][j] = 0;
upf[i][j] = inf;
}
}
int row,col,lim;
char op;
for(int i = 1;i <= limitnum;++i)
{
scanf("%d %d %c %d",&row,&col,&op,&lim);
if(row == 0 && col == 0)
{
for(int i = 1;i <= n;++i)
{
for(int j = 1;j <= m;++j)
{
addlimit(i,j,op,lim);
}
}
}
else if(row == 0)
{
for(int i = 1;i <= n;++i)
{
addlimit(i,col,op,lim);
}
}
else if(col == 0)
{
for(int i = 1;i <= m;++i)
{
addlimit(row,i,op,lim);
}
}
else
{
addlimit(row,col,op,lim);
}
}
根据上下界数组,添加有上下界边
int tot = 0;
for(int i = 1;i <= n;++i)
{
for(int j = 1;j <= m;++j)
{
addflow(i,n+j,lowf[i][j],upf[i][j],++tot);
}
}
加边完成后,转化为无源汇有上下界可行流 ———— 循环流
add(t,s,inf,0);
int sum = 0;
for(int i = s;i <= t;++i)
{
if(upflow[i] < 0)
{
add(i,tt,-upflow[i],0);
}
else
{
sum += upflow[i];
add(ss,i,upflow[i],0);
}
}
跑DIinc,如果存在可行流的话
就输出叭~~
for(int now = n+1;now <= n + m;++now)
{
for(int i = id[now];~i;i = e[i].pre)
{
int to = e[i].to;
int lid = e[i].lid;
if(lid == 0 || i % 2 == 0)continue;
out[to][now-n] = lowf[to][now-n] + e[i].val;
}
}
for(int i = 1;i <= n;++i)
{
for(int j = 1;j <= m;++j)
{
if(j == 1)
printf("%d",out[i][j]);
else
printf(" %d",out[i][j]);
}
printf("\n");
}
完整代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#define inf (1 << 28)
using namespace std;
const int maxn = 25;
const int maxm = 210;
const int mn = 505;
const int mm = 440020;
struct node{
int to,val,pre,lid;
}e[mm];
int id[mn],cnt=0; int cur[mn];
int flor[mn]; int upflow[mn];
int lowf[maxm][maxn];
int upf[maxm][maxn];
int out[maxm][maxn];
void init()
{
memset(id,-1,sizeof(id));
memset(upflow,0,sizeof(upflow));
cnt = 0;
}
void add(int from,int to,int val,int lid)
{
e[cnt].to = to;
e[cnt].val = val;
e[cnt].lid = lid;
e[cnt].pre = id[from];
id[from] = cnt++;
swap(from,to);
e[cnt].to = to;
e[cnt].val = 0;
e[cnt].lid = lid;
e[cnt].pre = id[from];
id[from] = cnt++;
}
void addflow(int from,int to,int low,int up,int lid)
{
upflow[from] -= low;
upflow[to] += low;
add(from,to,up-low,lid);
}
bool bfs(int s,int t)
{
memset(flor,0,sizeof(flor));
flor[s] = 1;
queue<int> q;
while(q.size())q.pop(); q.push(s);
while(q.size())
{
int now = q.front();
q.pop(); for(int i = id[now];~i;i = e[i].pre)
{
int to = e[i].to;
int val = e[i].val;
if(val > 0 && flor[to] == 0)
{
flor[to] = flor[now] + 1;
q.push(to);
if(to == t)
return true;
}
}
}
return false;
}
int dfs(int s,int t,int value)
{
if(s == t || value == 0)return value; int ret = value,a; for(int &i = cur[s];~i;i = e[i].pre)
{
int val = e[i].val;
int to = e[i].to;
if(flor[to] == flor[s] + 1 && (a = dfs(to,t,min(ret,val))))
{
e[i].val -= a;
e[i^1].val += a;
ret -= a;
if(ret == 0)break;
}
}
if(ret == value)flor[s] = 0;
return value - ret;
} int Dinic(int s,int t)
{
int ret = 0;
while(bfs(s,t))
{
memcpy(cur,id,sizeof(id));
ret += dfs(s,t,inf);
}
return ret;
} void addlimit(int i,int j,char op,int lim)
{
if(op == '=')
{
upf[i][j] = lowf[i][j] = lim;
}
else if(op == '>')
{
lowf[i][j] = max(lowf[i][j],lim+1);
}
else
{
upf[i][j] = min(upf[i][j],lim-1);
}
}
int main()
{
int T;
scanf("%d",&T);
int n,m,s,t,ss,tt;
while(T--)
{
init();
scanf("%d%d",&n,&m);
s = 0;
t = n + m + 1;
ss = t + 1;
tt = ss + 1;
int lsum;
for(int i = 1;i <= n;++i)
{
scanf("%d",&lsum);
addflow(s,i,lsum,lsum,0);
}
for(int i = 1;i <= m;++i)
{
scanf("%d",&lsum);
addflow(n + i,t,lsum,lsum,0);
}
int limitnum;
scanf("%d",&limitnum);
for(int i = 1;i <= n;++i)
{
for(int j = 1;j <= m;++j)
{
lowf[i][j] = 0;
upf[i][j] = inf;
}
}
int row,col,lim;
char op;
for(int i = 1;i <= limitnum;++i)
{
scanf("%d %d %c %d",&row,&col,&op,&lim);
if(row == 0 && col == 0)
{
for(int i = 1;i <= n;++i)
{
for(int j = 1;j <= m;++j)
{
addlimit(i,j,op,lim);
}
}
}
else if(row == 0)
{
for(int i = 1;i <= n;++i)
{
addlimit(i,col,op,lim);
}
}
else if(col == 0)
{
for(int i = 1;i <= m;++i)
{
addlimit(row,i,op,lim);
}
}
else
{
addlimit(row,col,op,lim); }
}
int tot = 0;
for(int i = 1;i <= n;++i)
{
for(int j = 1;j <= m;++j)
{
addflow(i,n+j,lowf[i][j],upf[i][j],++tot);
}
}
add(t,s,inf,0);
int sum = 0;
for(int i = s;i <= t;++i)
{
if(upflow[i] < 0)
{
add(i,tt,-upflow[i],0);
}
else
{
sum += upflow[i];
add(ss,i,upflow[i],0);
}
}
if(Dinic(ss,tt) == sum)
{
for(int now = n+1;now <= n + m;++now)
{
for(int i = id[now];~i;i = e[i].pre)
{
int to = e[i].to;
int lid = e[i].lid;
if(lid == 0 || i % 2 == 0)continue;
out[to][now-n] = lowf[to][now-n] + e[i].val;
}
}
for(int i = 1;i <= n;++i)
{
for(int j = 1;j <= m;++j)
{
if(j == 1)
printf("%d",out[i][j]);
else
printf(" %d",out[i][j]);
}
printf("\n");
}
}
else
{
printf("IMPOSSIBLE\n");
}
if(T)printf("\n");
}
return 0;
}
ZOJ1994有源汇上下界可行流的更多相关文章
- POJ2396 Budget [有源汇上下界可行流]
POJ2396 Budget 题意:n*m的非负整数矩阵,给出每行每列的和,以及一些约束关系x,y,>=<,val,表示格子(x,y)的值与val的关系,0代表整行/列都有这个关系,求判断 ...
- 有源汇上下界可行流(POJ2396)
题意:给出一个n*m的矩阵的每行和及每列和,还有一些格子的限制,求一组合法方案. 源点向行,汇点向列,连一条上下界均为和的边. 对于某格的限制,从它所在行向所在列连其上下界的边. 求有源汇上下界可行流 ...
- 计蒜客 31447 - Fantastic Graph - [有源汇上下界可行流][2018ICPC沈阳网络预赛F题]
题目链接:https://nanti.jisuanke.com/t/31447 "Oh, There is a bipartite graph.""Make it Fan ...
- poj2396 Budget(有源汇上下界可行流)
[题目链接] http://poj.org/problem?id=2396 [题意] 知道一个矩阵的行列和,且知道一些格子的限制条件,问一个可行的方案. [思路] 设行为X点,列为Y点,构图:连边(s ...
- 算法复习——有源汇上下界可行流(bzoj2396)
题目: Description We are supposed to make a budget proposal for this multi-site competition. The budge ...
- poj2396有源汇上下界可行流
题意:给一些约束条件,要求算能否有可行流,ps:刚开始输入的是每一列和,那么就建一条上下界相同的边,这样满流的时候就一定能保证流量相同了,还有0是该列(行)对另一行每个点都要满足约束条件 解法:先按无 ...
- bzoj 2406 矩阵 —— 有源汇上下界可行流
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2406 这题,首先把题目那个式子的绝对值拆成两个限制,就成了网络流的上下界: 有上下界可行流原 ...
- bzoj千题计划158:bzoj2406: 矩阵(有源汇上下界可行流)
http://www.lydsy.com/JudgeOnline/problem.php?id=2406 设矩阵C=A-B 最小化 C 一行或一列和的最大值 整体考虑一行或者一列的和 二分最大值 这样 ...
- poj2396 Budget&&ZOJ1994 Budget[有源汇上下界可行流]
Budget Time Limit: 5 Seconds Memory Limit: 32768 KB Special Judge We are supposed to make ...
随机推荐
- Python学习—基础篇之基本数据类型(二)
Python中重要的数据结构 1.列表 2.元组 3.字典 4.集合 列表 1.创建列表 # 方式一 name = [] print(type(name)) # 执行结果 >>> & ...
- python之全局变量与局部变量
全局变量: - 在书写中顶格开始: - 一旦定义完毕在整个文件生效: - 在函数内如果定义了同名全局变量名,会“覆盖”掉全局变量: - 在函数中同名的变量,当在函数退出后消失,全局的同 ...
- python 获取随机字母
Python2 #-*- coding:utf- -*- import string #导入string这个模块 print string.digits #输出包含数字0~9的字符串 print st ...
- 生成式对抗网络(GAN)实战——书法字体生成练习赛
https://www.tinymind.cn/competitions/ai 生成式对抗网络(GAN)是近年来大热的深度学习模型. 目前GAN最常使用的场景就是图像生成,作为一种优秀的生成式模型,G ...
- checkpoint防火墙SmartDashboard登录出错
SmartDashboard登录是报错:fingerprint不匹配 原因:主备机切换导致 解决:选择凌晨不影响业务的时间拔掉原备机的电源线.
- hbase-运维命令
hbase 问题 不一致问题 meta表不一致问题 hdfs文件不一致问题 hbase hbck hbase hbck 用于检测和修改hbase底层文件问题.检测像master,region serv ...
- fmt.printf输出的格式
动 词 功 能 %v 按值的本来值输出 %+v 在 %v 基础上,对结构体字段名和值进行展开 %#v 输出 Go 语言语法格式的值 %T 输出 Go 语言语法格式的类型和值 %% 输出 % 本体 %b ...
- Ubuntu 18.04 下如何配置mysql 及 配置远程连接
首先是大家都知道的老三套,啥也不说上来就放三个大招: sudo apt-get install mysql-server sudo apt isntall mysql-client sudo apt ...
- 堆&栈的理解(转)
(摘自:http://www.cnblogs.com/likwo/archive/2010/12/20/1911026.html) C++中堆和栈的理解 内存分配方面: 堆: 操作系统有一个记录空闲内 ...
- docker构建镜像
Docker 提供了两种构建镜像的方法: docker commit 命令Dockerfile 构建文件 示例: Dockerfile FROM golang:1.7.5 #基础镜像 RUN apt- ...