CDOJ 1962 天才钱vs学霸周2【最大流】
以s=0,t=n+m+1分别为超级源点和超级汇点。网络流中的流量以0为开始,题目要求从1到20,我们先把每个点都减去1,即ai - m,bi - n。然后源点s与n个顶点连容量为ai的路,汇点t与m个顶点连容量为bi的路,n个顶点再与m个顶点连接19的容量。最后再跑下Dinic,如果最后汇聚到t的流量和总值相同,输出“Yes”,否则输出“No”。最后输出对应边的答案,可以用残余网络来计算,用19-残余的容量即该条边的流量。
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std; const int N=;
const int M=N*N;
const int INF = 0x3f3f3f3f;
int s,t,n,m,cnt;
int a[N],b[N];
int Head[N],Depth[N],Next[M],V[M],W[M]; void init()
{
cnt=-;
memset(Head,-,sizeof(Head));
memset(Next,-, sizeof(Next));
} void add_edge(int u,int v,int w)
{
cnt++;Next[cnt]=Head[u];V[cnt]=v;W[cnt]=w;Head[u]=cnt;
cnt++;Next[cnt]=Head[v];V[cnt]=u;W[cnt]=;Head[v]=cnt; // 反向边
} bool bfs()
{
queue<int> q;
while(!q.empty())q.pop();
memset(Depth,, sizeof(Depth));
q.push(s);
Depth[s]=;
while(!q.empty())
{
int u=q.front();q.pop();
for(int i=Head[u];i!=-;i=Next[i])
{
if(W[i]>&&Depth[V[i]]==)
{
Depth[V[i]]=Depth[u]+;
q.push(V[i]);
}
}
}
if(Depth[t]==)return false;
else return true;
} int dfs(int u,int flow)
{
if(u==t)return flow;
int rest = flow;
for(int i=Head[u];i!=-;i=Next[i])
{
if(Depth[V[i]]==Depth[u]+&&W[i]>)
{
int k=dfs(V[i],min(W[i],rest));
if(!k)Depth[V[i]]=; // 剪枝,去掉增广完毕的点
W[i]-=k;
W[i^]+=k;
rest-=k;
}
}
return flow-rest;
} int Dinic()
{
int ans=;
while(bfs()) // 在残量网络上构造分层图
{
while(int flow = dfs(s,INF)) // 在当前分层图上增广
ans+=flow;
}
return ans;
} void print()
{
int res[N][N];
memset(res,,sizeof(res));
for(int i=;i<=n;i++)
for(int j=Head[i];j!=-;j=Next[j])
{
int v=V[j];
if(v>n&&v<=n+m)res[i][v-n]=-W[j]+;
}
for(int i=;i<=n;i++){
for(int j=;j<=m;j++){
printf("%d",res[i][j]);
if(j==m) printf("\n");
else printf(" ");
}
}
} int main(){
init();
scanf("%d%d",&n,&m);
s=;t=n+m+; for(int i=;i<=n;i++){
scanf("%d",&a[i]);a[i]-=m;
add_edge(s,i,a[i]);
}
for(int i=;i<=m;i++){
scanf("%d",&b[i]);b[i]-=n;
add_edge(n+i,t,b[i]);
} for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
add_edge(i,n+j,); int c1=,c2=,c3=;
for(int i=;i<=n;i++) c1+=a[i];
for(int i=;i<=m;i++) c2+=b[i];
if(c1!=c2) printf("No\n");
else{
c3=Dinic();
if(c3!=c2) printf("No\n");
else{
printf("Yes\n");
print();
}
}
return ;
}
附:Edmonds-Karp增广路算法模板: 不断用BFS寻找增广路,直至网络上不存在增广路为止
const int inf = <<,N=,M=;
int head[N],ver[M],edge[M],Next[M],v[N],incf[N],pre[N];
int n,m,s,t,tot,maxflow; void add(int x,int y,int z)
{
tot++,ver[tot]=y,edge[tot]=z,Next[tot]=head[x],head[x]=tot; // 邻接表的数组写法
tot++,ver[tot]=x,edge[tot]=,Next[tot]=head[y],head[y]=tot; //反向边,edge剩余容量
} bool bfs()
{
memset(v,, sizeof(v));
queue<int> q;
q.push(s);v[s]=;
incf[s]=inf; // 增广路上个边的最小剩余容量
while(q.size())
{
int x = q.front();
q.pop();
for(int i=head[x];i;i=Next[i])
{
if(edge[i])
{
int y=ver[i];
if(v[y])continue;
incf[y]=min(incf[x],edge[i]);
pre[y]=i; // 记录前驱(当前的tot序号,偶奇成对存储,抑或操作可导出前驱)
q.push(y);
v[y]=;
if(y==t)return ; // 可达t点
}
}
}
return ;
} void update()// 更新一条增广路及其反向边的剩余容量
{
int x = t;
while(x!=s)
{
int i=pre[x];
edge[i]-=incf[t];
edge[i^]+=incf[t];
x = ver[i^]; // 前驱节点
}
maxflow+=incf[t];
} int main()
{
while(cin>>m>>n)
{
memset(head,, sizeof(head));
s=,t=n;tot=;maxflow=;
for(int i=;i<=m;i++)
{
int x,y,c;
scanf("%d%d%d",&x,&y,&c);
add(x,y,c);
}
while(bfs())update();
cout<<maxflow<<endl;
}
}
CDOJ 1962 天才钱vs学霸周2【最大流】的更多相关文章
- 矩阵解压,网络流UESTC-1962天才钱vs学霸周2
天才钱vs学霸周2 Time Limit: 500 MS Memory Limit: 128 MB Submit Status 由于上次的游戏中学霸周输了,因此学霸周想出个问题为难天才钱,问题 ...
- 最小生成树唯一性判断-UESTC1959天才钱vs学霸周
天才钱vs学霸周 Time Limit: 1000 MS Memory Limit: 256 MB Submit Status 有一天,天才钱和学霸周闲的无聊玩起了游戏,游戏内容是这样的,现在 ...
- 度及拓扑图的使用-UESTC1958学霸周选课
学霸周选课 Time Limit: 1000 MS Memory Limit: 128 MB Submit Status 众所周知周大爷不仅编程了得,专业课成绩更是名列前茅,恰巧又到了选课的季 ...
- 【P1379】天才的约数和
来自GDOI2007,原题已不可考-- 又自己做出来了好开心,找特殊性是个关键的切入点 原题: 这天周航遇到了靳泽旭. 周航:"我是天才!" 靳泽旭:"你为什么是天才?& ...
- Python-week2,第二周(基于Python3.0以上)
1,列表 存储数据我们可以使用变量,但是当有很多个数据的时候用变量就会出现很多的局限性,所以这时候就用到了列表.列表就是中括号里每个元素使用逗号隔开.列如 [1,2,3] 这就是一个列 ...
- 【Win 10 应用开发】获取本机的IP地址
按照老规矩,也是朋友的建议,老周今天在吹牛之前,先讲一个小故事. 有朋友问我,老周,你现在还发短信吗,你每个月用多少电话费?唉,实话说,现在真的发短信不多了,套餐送的130条短信,每月都发不了一条.至 ...
- java List的排序
List自定义排序 1.第一种方法,就是list中对象实现Comparable接口,重写compareTo接口, 对排序的字段进行比较.2.第二种方法,就是在重载Collections.sort方法. ...
- js 随机生成姓名、手机号、身份证号、银行卡号
开发测试的时候,经常需要填写姓名.手机号.身份证号.银行卡号,既要符合格式要求.又不能重复.大家会到网上搜各种生成器.能不能自己写一个简单的生成器呢.下面是随机生成姓名.手机号.身份证号.银行卡号的j ...
- C# 写的一个生成随机汉语名字的小程序
最近因为要做数据库相关的测试,频繁使用到测试数据,手动添加太过于麻烦,而且复用性太差,因此干脆花了点时间写了一个生成随机姓名和相关数据的类,贴在这里,有需用的同志们可以参考一下.代码本身质量不好,也不 ...
随机推荐
- 10 个 MySQL 经典错误【转】
Top 1:Too many connections(连接数过多,导致连接不上数据库,业务无法正常进行) 问题还原 mysql> show variables like '%max_connec ...
- xpath 中 [<Element a at 3985984dj343>]
在写爬虫用xpath抓取数据的时候出现了这个问题,列表中都是很多个 < element > 首先这不是报错,也不是你的xpath语法有错. 将这个数据列表循环,循环出的item就是你想要的 ...
- 设计模式C++学习笔记之十(Builder建造者模式)
建造者模式,将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示.一段晦涩难懂的文字,实现创建不同表示的方法就是给创建的过程传入创建的参数.详细的还是看代码吧. 10.1.解释 ...
- python 创建二维数组
myList = [([0] * 3) for i in range(4)] myList[0][1] = 1 myList[1].append(2) print myList /usr/bin/py ...
- live555运行时报错:StreamParser internal error ( 86451 + 64000 > 150000)
搭建好live555服务器后,使用 vlc播放网络视频.此时服务器端报如下错误: StreamParser internal error ( 86451 + 64000 > 150000). ...
- 快速解决PHP调用Word组件DCOM权限的问题
1. 首先必须要在电脑上安装 Office 2. windows+r : 输入 dcomcnfg.exe 打开组件服务,然后双击 组件服务 ==> 双击 计算机 ==> 双击 我的电脑 = ...
- .NET基础之构造函数
1.构造函数: 分为实例构造函数.静态构造函数.私有构造函数. 使用new表达式创建某个类的对象时, 1.1实例构造函数: (1)构造函数的名字与类名相同: (2)使用new表达式创建类的对象或者结构 ...
- python学习第11天 迭代器
函数的名称 闭包 迭代器 递归
- Linux中给普通用户添加sudo权限
使用Linux系统时,经常会被要求使用超级权限,但是root的权限太过大了,一般慎用!!!因此可以通过给普通用户添加sudo权限,平常用普通用户进行操作,当需要root权限的时候进行sudo操作.以下 ...
- Laravel 5.2服务----用户验证Auth相关问题
关于laravel的auth()用户认证这一块,面前我也是,有用到,有碰到什么问题我就记录下来. 手动认证用户 <?php namespace App\Http\Controllers; use ...