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 ...
随机推荐
- Android Toast 工具类
android 中常用系统吐司工具类 package cn.yhq.utils; import android.content.Context; import android.widget.Toas ...
- select2的设置选中
select2插件设置选中值并显示的问题 在select2中,要想设置指定值为选中状态并显示: $("#select2_Id").val("XXXXX").se ...
- HTTPClient to use http/https protocol to send request
使用了spring boot, gradle, commons-httpcomponent3. 目前httpclient 已经有了版本4. https://github.com/lvfe/httpCl ...
- swift UIview上添加视频播放
1. /// 是否显示过广告 private lazy var isLoadAV = false /// 15秒宣传视频 private var play: AVPlayer? /// 宣传视频背景 ...
- odoo qweb 记录
默认的打印功能修改,比如在动作中的打印功能: 继承抽象模型 models.AbstractModel 重写 _get_report_values class PayslipDetailsReportI ...
- go语言学习逻辑运算符if判断,iota的理解
第一天学习go语言,首先吐槽一下,配置go语言浪费了我两个小时的时间 不是在百度,就是在百度的路上,这里介绍一下我的go语言的版本和开发平台 go语言1.12版本,之前没有用过在早的版本了首先记录一下 ...
- 爬取qq号
import reimport urllib.requestimport osimport jsonimport sslfrom collections import deque #把爬去的数据保存到 ...
- 用SAX解析xml文件,java
(此文为(https://www.imooc.com/video/4482)之随笔) 1.用SAX解析xml文件大致分为三步 写了一个XML文件作为例子 (1)main方法代码如下: import j ...
- si_da
1. apt-get 从互联网的软件仓库中搜索.安装.升级.卸载软件或操作系统 一般需要root权限执行,所以一般跟着sudo命令 sudo ifstat apt-get install -y ifs ...
- 浅谈Java和PHP的异同
编程范式: Java:纯面向对象的语言,有人说过:Java中一切皆对象!当然咯,人们都忘了Java的八种基本数据类型:int.double.boolean.byte.float.long.short. ...