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 ...
随机推荐
- 登录注册页面(连接MySQL8.0.15版本)
原文链接:https://mp.weixin.qq.com/s?__biz=MzI4Njg5MDA5NA==&mid=2247483779&idx=1&sn=e23e68e96 ...
- 第三周博客总结 <西北师范大学| 周安伟>
一,本周助教小结 工作稳步推进,时间分配合理,点评效率有所提高,主要进行了评分工作,工作情况都汇总到了Excel中. 二,助教本人博客 https://home.cnblogs.com/u ...
- iTerm2使用技巧
iTerm2实用技巧 搜索及文本复制 使用“cmd+f”可以调出搜索框进行文本搜索,然后有个很奇妙的快捷键“tab”键,使用它后会自动高亮当前文本后面的内容.最后按enter键将高亮文本复制到剪切板上 ...
- Python入门day04_函数与装饰器
一.函数入门 什么是函数: # 函数:函数是一系列代码的集,用来完成特定功能的代码块,类似于工具,可以重复不但的去使用 为什么要有函数: # 优点:# 1. 避免代码的冗余 # 2. 让程序代码结构更 ...
- Spring--基础介绍一:IOC和DI
前面学习了Struts2和Hibernate. Struts2主要是用来控制业务层面逻辑和显示,告诉你什么时候走哪个action,跑去运行哪个class的什么方法,后面调到哪个jsp. Struts2 ...
- echarts 图表重新加载,原来的数据依然存在图表上
问题 在做一个全国地图上一些饼图,并且向省一级的地图钻取的时候,原来的饼图依然显示 原因 echars所有添加的图表都在一个series属性集合中,并且同一个echars对象默认是合并之前的数据的,所 ...
- Thread类与Runnable接口的深入理解
Thread类与Runnable接口的深入理解1.Thread类实现了Runnable接口,实现run方法,其中target参数对应的就是一个Runnable接口的实现类 @Override publ ...
- SNORT入侵检测系统
SNORT入侵检测系统 YxWa · 2015/10/09 10:38 0x00 一条简单的规则 alert tcp 202.110.8.1 any -> 122.111.90.8 80 (ms ...
- tomcat修改banner,隐藏版本号
为了避免黑客针对某些版本进行攻击,因此我们需要隐藏或者伪装 Tomcat 的版本信息.针对该信息的显示是由一个jar包控制的,该jar包存放在 Tomcat 安装目录下的lib目录下,名称为 cata ...
- Django实现文件的上传
Django实现文件的上传 1.前端页面:使用file对象,读取文件对象传递到views中.需要设定enctype="multipart/form-data",表明不对字符进行编码 ...