poj1149构图题
引题解:
这道题目的大意是这样的:
⦁ 有 M 个猪圈(M ≤ 1000),每个猪圈里初始时有若干头猪。
⦁ 一开始所有猪圈都是关闭的。
⦁ 依次来了 N 个顾客(N ≤ 100),每个顾客分别会打开指定的几个猪圈,从中买若干头猪。
⦁ 每个顾客分别都有他能够买的数量的上限。
⦁ 每个顾客走后,他打开的那些猪圈中的猪,都可以被任意地调换到其它开着的猪圈里,然后所有猪圈重新关上。
问总共最多能卖出多少头猪。
举个例子来说。有 3 个猪圈,初始时分别有 3、 1 和 10 头猪。依次来了 3 个顾客,第一个打开 1 号 和 2 号猪圈,最多买 2 头;第二个打开 1 号 和 3 号猪圈,最多买 3 头;第三个打开 2 号猪圈,最多买 6 头。那么,最好的可能性之一就是第一个顾客从 1 号圈买 2 头,然后把 1 号圈剩下的 1 头放到 2 号圈;第二个顾客从 3 号圈买 3 头;第三个顾客从 2 号圈买 2 头。总共卖出 2 + 3 + 2 = 7 头。
不难想像,这个问题的网络模型可以很直观地构造出来。就拿上面的例子来说,可以构造出图 1 所示的模型(图中凡是没有标数字的边,容量都是 +∞):
⦁ 三个顾客,就有三轮交易,每一轮分别都有 3 个猪圈和 1 个顾客的节点。
⦁ 从源点到第一轮的各个猪圈各有一条边,容量就是各个猪圈里的猪的初始数量。
⦁ 从各个顾客到汇点各有一条边,容量就是各个顾客能买的数量上限。
⦁ 在某一轮中,从该顾客打开的所有猪圈都有一条边连向该顾客,容量都是 +∞。
⦁ 最后一轮除外,从每一轮的 i 号猪圈都有一条边连向下一轮的 i 号猪圈,容量都是 +∞,表示这一轮剩下的猪可以留到下一轮。
⦁ 最后一轮除外,从每一轮被打开的所有猪圈,到下一轮的同样这些猪圈,两两之间都要连一条边,表示它们之间可以任意流通。

图 1
不难想像,这个网络模型的最大流量就是最多能卖出的数量。图中最多有 2 + N + M × N ≈ 100,000 个节点。
这个模型虽然很直观,但是节点数太多了,计算速度肯定会很慢。其实不用再想别的算法,就让我们继续上面的例子,用合并的方法来简化这个网络模型。
首先,最后一轮中没有打开的猪圈就可以从图中删掉了,也就是图 2 中红色的部分,显然它们对整个网络的流量没有任何影响。

图 2
接着,看图 2 中蓝色的部分。根据我总结出的以下几个规律,可以把这 4 个点合并成一个:
规律 1. 如果几个节点的流量的来源完全相同,则可以把它们合并成一个。
规律 2. 如果几个节点的流量的去向完全相同,则可以把它们合并成一个。
规律 3. 如果从点 u 到点 v 有一条容量为 +∞ 的边,并且 u 是 v 的唯一流量来源,或者 v 是 u 的唯一流量去向,则可以把 u 和 v 合并成一个节点。
根据规律 1,可以把蓝色部分右边的 1、 2 号节点合并成一个;根据规律 2,可以把蓝色部分左边的 1、 2 号节点合并成一个;最后,根据规律 3,可以把蓝色部分的左边和右边(已经分别合并成了一个节点)合并成一个节点。于是,图 2 被简化成了图 3 的样子。也就是说,最后一轮除外,每一轮被打开的猪圈和下一轮的同样这些猪圈都可以被合并成一个点。

图 3
接着,根据规律 3,图 3 中的蓝色节点、2 号猪圈和 1 号顾客这三点可以合并成一个;图 3 中的两个 3 号猪圈和 2 号顾客也可以合并成一个点。当然,如果两点之间有多条同向的边,则这些边可以合并成一条,容量相加,这个道理很简单,就不用我多说了。最终,上例中的网络模型被简化成了图 4 的样子。

图 4
让我们从图 4 中重新总结一下构造这个网络模型的规则:
⦁ 每个顾客分别用一个节点来表示。
⦁ 对于每个猪圈的第一个顾客,从源点向他连一条边,容量就是该猪圈里的猪的初始数量。如果从源点到一名顾客有多条边,则可以把它们合并成一条,容量相加。
⦁ 对于每个猪圈,假设有 n 个顾客打开过它,则对所有整数 i ∈ [1, n),从该猪圈的第 i 个顾客向第 i + 1 个顾客连一条边,容量为 +∞。
⦁ 从各个顾客到汇点各有一条边,容量是各个顾客能买的数量上限。
拿我们前面一直在讲的例子来说:1 号猪圈的第一个顾客是 1 号顾客,所以从源点到 1 号顾客有一条容量为 3 的边;1 号猪圈的第二个顾客是 2 号顾客,因此从 1 号顾客到 2 号顾客有一条容量为 +∞ 的边;2 号猪圈的第一个顾客也是 1 号顾客,所以从源点到 1 号顾客有一条容量为 1 的边,和之前已有的一条边合并起来,容量变成 4;2 号猪圈的第二个顾客是 3 号顾客,因此从 1 号顾客到 3 号顾客有一条容量为 +∞ 的边;3 号猪圈的第一个顾客是 2 号顾客,所以从源点到 2 号顾客有一条容量为 10 的边。
新的网络模型中最多只有 2 + N = 102 个节点,计算速度就可以相当快了。可以这样理解这个新的网络模型:对于某一个顾客,如果他打开了猪圈 h,则在他走后,他打开的所有猪圈里剩下的猪都有可能被换到 h 中,因而这些猪都有可能被 h 的下一个顾客买走。所以对于一个顾客打开的所有猪圈,从该顾客到各猪圈的下一个顾客,都要连一条容量为 +∞ 的边。
在面对网络流问题时,如果一时想不出很好的构图方法,不如先构造一个最直观,或者说最“硬来”的模型,然后再用合并节点和边的方法来简直化这个模型。经过简化以后,好的构图思路自然就会涌现出来了。这是解决网络流问题的一个好方法。
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<queue>
using namespace std;
const int maxn=,maxm=,inf=0x7fffffff;
int n,m,a,b,c,s,t,tot=,maxflow,pig[],cstm[][],head[maxn],cur[maxn],h[maxn];
bool vis[][];
queue<int> q;
struct node{
int go,next,v;
}e[maxm];
inline int read(){
int x=,f=;char ch=getchar();
while (ch>'' || ch<''){if (ch=='-') f=-;ch=getchar();}
while (ch>='' && ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
inline void addedge(int x,int y,int v){
e[++tot]=(node){y,head[x],v};head[x]=tot;
e[++tot]=(node){x,head[y],};head[y]=tot;
}
bool bfs(){
for (int i=s;i<=t;i++) h[i]=-;
q.push(s);h[s]=;
while (!q.empty()){
int x=q.front();q.pop();
for (int i=head[x];i;i=e[i].next){
if (e[i].v&&h[e[i].go]==-){
h[e[i].go]=h[x]+;
q.push(e[i].go);
}
}
}
return h[t]!=-;
}
int dfs(int x,int f){
if (x==t) return f;
int tmp,used=;
for (int i=cur[x];i;i=e[i].next){
if (e[i].v&&h[e[i].go]==h[x]+){
tmp=dfs(e[i].go,min(e[i].v,f-used));
e[i].v-=tmp;if (e[i].v) cur[x]=i;
e[i^].v+=tmp;used+=tmp;
if (used==f) return f;
}
}
if (!used) h[x]=-;
return used;
}
void dinic(){
maxflow=;
while (bfs()){
for (int i=s;i<=t;i++) cur[i]=head[i];
maxflow+=dfs(s,inf);
}
}
int main(){
m=read();n=read();
s=;t=n+;
for (int i=;i<=m;i++) pig[i]=read();
for (int i=;i<=n;i++){
a=read();
for (int j=;j<=a;j++){
c=read();
cstm[c][++cstm[c][]]=i+;
}
c=read();
addedge(i+,t,c);
}
for (int i=;i<=m;i++){
if (cstm[i][]){
addedge(s,cstm[i][],pig[i]);
for (int j=;j<=cstm[i][];j++){
if (!vis[cstm[i][j-]][cstm[i][j]]) vis[cstm[i][j-]][cstm[i][j]]=,addedge(cstm[i][j-],cstm[i][j],inf);
}
}
}
dinic();
printf("%d\n",maxflow);
}
poj1149构图题的更多相关文章
- poj3281构图题
题目大意:有F种食物,D种饮料N头奶牛,只能吃某种食物和饮料(而且只能吃特定的一份)一种食物被一头牛吃了之后,其余牛就不能吃了第一行有N,F,D三个整数接着2-N+1行代表第i头牛,前面两个整数是Fi ...
- 【转载】图论 500题——主要为hdu/poj/zoj
转自——http://blog.csdn.net/qwe20060514/article/details/8112550 =============================以下是最小生成树+并 ...
- [转] POJ图论入门
最短路问题此类问题类型不多,变形较少 POJ 2449 Remmarguts' Date(中等)http://acm.pku.edu.cn/JudgeOnline/problem?id=2449题意: ...
- POJ 3469 Dual Core CPU (最小割建模)
题意 现在有n个任务,两个机器A和B,每个任务要么在A上完成,要么在B上完成,而且知道每个任务在A和B机器上完成所需要的费用.然后再给m行,每行 a,b,w三个数字.表示如果a任务和b任务不在同一个机 ...
- Soj题目分类
-----------------------------最优化问题------------------------------------- ----------------------常规动态规划 ...
- [HNOI 2001]软件开发
Description 某软件公司正在规划一项n天的软件开发计划,根据开发计划第i天需要ni个软件开发人员,为了提高软件开发人员的效率,公司给软件人员提供了很多的服务,其中一项服务就是要为每个开发人员 ...
- 【HDOJ图论题集】【转】
=============================以下是最小生成树+并查集====================================== [HDU] How Many Table ...
- SPOJ IM - Intergalactic Map - [拆点最大流]
题目链接:http://www.spoj.com/problems/IM/en/ Time limit:491 ms Memory limit:1572864 kB Code length Limit ...
- 图论常用算法之一 POJ图论题集【转载】
POJ图论分类[转] 一个很不错的图论分类,非常感谢原版的作者!!!在这里分享给大家,爱好图论的ACMer不寂寞了... (很抱歉没有找到此题集整理的原创作者,感谢知情的朋友给个原创链接) POJ:h ...
随机推荐
- java中异常处理
看到一篇异常处理的好文章: Java异常处理机制主要依赖于try,catch,finally,throw,throws五个关键字. try 关键字后紧跟一个花括号括起来的代码块,简称try块.同理:下 ...
- HTML5-canvas1.0
HTML5 <canvas> 元素用于图形的绘制,通过脚本 (通常是JavaScript)来完成.<canvas> 标签只是图形容器,您必须使用脚本来绘制图形.你可以通过多种方 ...
- SQL Server截取字符串
--SQL Server截取字符串 , Len('hello@163.com')) ,charindex('.','hello@163.com'))
- Python面向对象编程(上)
Python不仅支持面向过程编程,同时也支持面向对象编程.面向工程就是分析解决问题所需的步骤,然后用函数把这些步骤逐一实现,使用的时候再一个个调用函数就可以.面向对象则是把解决的问题按照一定规则划分为 ...
- faster rcnn源码阅读笔记1
自己保存的源码阅读笔记哈 faster rcnn 的主要识别过程(粗略) (开始填坑了): 一张3通道,1600*1600图像输入中,经过特征提取网络,得到100*100*512的feature ma ...
- Eclipse中创建一个新的SpringBoot项目
在Eclipse中创建一个新的spring Boot项目: 1. 首先在Eclipse中安装STS插件:在Eclipse主窗口中点击 Help -> Eclipse Marketplace... ...
- javascript中的类型检测
最常见的是使用 typeof 来判断数据类型 可以区分4种基本类型,即 “number”,”string”,”undefined”,”boolean”,第5种基本类型null类型返回值为object( ...
- python虚拟环境的搭建
使用python虚拟环境作用是项目与项目之间相互隔离,互相不受影响,比如当需要同时部署A.B两个项目时,A项目依赖C库的1.0版本,B项目依赖C库的2.0版本,假如不使用虚拟环境隔离A项目和B项目就很 ...
- 十一 hashlib模块
# 1.什么叫hash:hash是一种算法(3.x里代替了md5模块和sha模块,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法),该算法接受传入的 ...
- 使用__slots__节省python内存技巧
__slots__作用 __slots__有一个作用是:限制类实例绑定的属性,但是它有一个更重要的作用就是节省内存,当然更适用于数据量大的情况(万量级以上). __slots__节省内存的原理 cla ...