POJ 3281_Dining
题意:
FJ准备了F种食物和D种饮料,每头牛都有喜欢的食物和饮料,并且每头牛都只能分配一种食物和饮料。问如何分配使得同时得到喜欢的食物和饮料的牛数量最多。
分析:
首先想到将牛与其对应的食物和饮料匹配起来,即在食物、饮料与牛之间连一条边,再在s和所有食物之间、t和所有饮料之间连一条边。这样每一条路径都对应着食物饮料和牛之间的匹配方案。那么如何避免一头牛被分配多组匹配呢?就将一头牛拆成两个结点,并用一条容量为1的边连接起来,这样求出构成的图中的最大流,即得解。这里使用的是Dinic算法。
代码:
#include<cstdio>
#include<vector>
#include<cstring>
#include<queue>
using namespace std;
struct edge{int to, cap, rev;};
const int maxn = 105, maxm = 2000055, INF = 0x3fffffff;
int d[maxm], iter[maxm];
int s, t;
vector<edge>G[maxm];
int dr[maxn][maxn], f[maxn][maxn];
void add_edge(int from, int to, int cap)
{
G[from].push_back((edge){to, cap, G[to].size()});
G[to].push_back((edge){from, 0, G[from].size()-1});
}
void bfs()
{
memset(d, -1, sizeof(d));
queue<int>q;
d[s] = 0;
q.push(s);
while(!q.empty()){
int v = q.front();q.pop();
for(int i = 0; i <G[v].size(); i++){
edge &e = G[v][i];
if(e.cap>0&&d[e.to]<0){
d[e.to] = d[v] + 1;
q.push(e.to);
}
}
}
}
int dfs(int v, int f)
{
if(v==t) return f;
for(int &i = iter[v]; i < G[v].size(); i++){
edge &e = G[v][i];
if(e.cap > 0 && d[v] < d[e.to]){
int tf = dfs(e.to, min(f, e.cap));
if(tf > 0){
e.cap -= tf;
G[e.to][e.rev].cap +=tf;
return tf;
}
}
}
return 0;
}
int max_flow()
{
int flow = 0;
for(;;){
bfs();
if(d[t]<0) return flow;
memset(iter, 0, sizeof(iter));
int f;
while((f = dfs(s, INF))>0){
flow += f;
}
}
}
int main (void)
{
int N, F, D;scanf("%d%d%d",&N, &F, &D);
int a, b;
s = 2 * N + F + D + 1, t = s + 1;
for(int i = 1; i <= N; i++){
scanf("%d%d",&a, &b);
add_edge(i, N + i, 1);
for(int j = 0; j < a; j++){
scanf("%d",&f[i][j]);
add_edge(2 * N + f[i][j], i, 1);
}
for(int j = 0; j < b; j++){
scanf("%d",&dr[i][j]);
add_edge(N + i, 2 * N + F + dr[i][j], 1);
}
}
for(int i = 1; i <= F; i++)
add_edge(s, 2 * N + i, 1);
for(int i = 1; i <= D; i++)
add_edge(2 * N + F + i, t, 1);
printf("%d\n",max_flow());
}
增广路径必须满足的性质
1.有奇数条边。
2.起点在二分图的左半边,终点在右半边。
3.路径上的点一定是一个在左半边,一个在右半边,交替出现。(其实二分图的性质就决定了这一点,因为二分图同一边的点之间没有边相连,不要忘记哦。)
4.整条路径上没有重复的点。
5.起点和终点都是目前还没有配对的点,而其它所有点都是已经配好对的。
6.路径上的所有第奇数条边都不在原匹配中,所有第偶数条边都出现在原匹配中。
7.最后,也是最重要的一条,把增广路径上的所有第奇数条边加入到原匹配中去,并把增广路径中的所有第偶数条边从原匹配中删除(这个操作称为增广路径的取反),则新的匹配数就比原匹配数增加了1个(奇数=偶数+1)。
POJ 3281_Dining的更多相关文章
- POJ 3370. Halloween treats 抽屉原理 / 鸽巢原理
Halloween treats Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 7644 Accepted: 2798 ...
- POJ 2356. Find a multiple 抽屉原理 / 鸽巢原理
Find a multiple Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 7192 Accepted: 3138 ...
- POJ 2965. The Pilots Brothers' refrigerator 枚举or爆搜or分治
The Pilots Brothers' refrigerator Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 22286 ...
- POJ 1753. Flip Game 枚举or爆搜+位压缩,或者高斯消元法
Flip Game Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 37427 Accepted: 16288 Descr ...
- POJ 3254. Corn Fields 状态压缩DP (入门级)
Corn Fields Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 9806 Accepted: 5185 Descr ...
- POJ 2739. Sum of Consecutive Prime Numbers
Sum of Consecutive Prime Numbers Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 20050 ...
- POJ 2255. Tree Recovery
Tree Recovery Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 11939 Accepted: 7493 De ...
- POJ 2752 Seek the Name, Seek the Fame [kmp]
Seek the Name, Seek the Fame Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 17898 Ac ...
- poj 2352 Stars 数星星 详解
题目: poj 2352 Stars 数星星 题意:已知n个星星的坐标.每个星星都有一个等级,数值等于坐标系内纵坐标和横坐标皆不大于它的星星的个数.星星的坐标按照纵坐标从小到大的顺序给出,纵坐标相同时 ...
随机推荐
- xshell常用命令大全
xshell常用命令大全 (1)命令ls——列出文件 ls -la 给出当前目录下所有文件的一个长列表,包括以句点开头的“隐藏”文件 ls a* 列出当前目录下以字母a开头的所有文件 ls -l *. ...
- 移动web开发填坑(一)
上周开始接触移动web开发,默默的掉进了很多坑里面.本文主要总结本周遇到的坑以及如何填坑. 1.px与rem换算. 设计稿的宽度一般是640px,而iphone是320px,所以测量设计稿的结果首先要 ...
- 锐动SDK应用于行车记录仪
方案架构 手机端直播与录播功能忠实记录旅途中各种突发事件,还原事实真相,与家人和朋友分享沿途美景,一同感受美妙之旅. 强大的视频编辑功能,像编辑图片一样给视频添加各种滤镜,配音,配乐,标题文字等特效. ...
- Sql Server 2012 事务复制遇到的问题及解决方式
1.订阅服务器提示:作业失败.无法确定所有者 WIN-01Q6JB46CHV\Administrator(拥有作业XXX)是否有服务器访问权限(原因:无法获取有关 Windows NT 组/用户'WI ...
- asp.net 实现treeview 选中父节点其子节点也选种中 选中子节点其父节点与根节点也被选中
1.在 Page_Load(object sender, EventArgs e) 里面加入: TreeView1.Attributes.Add("onclick", " ...
- 数组(Arry)几个常用方法的详解
join() 方法用于把数组中的所有元素放入一个字符串.元素是通过指定的分隔符进行分隔的. arrayObject.join(separator)separator 可选.指定要使用的分隔符.如果省略 ...
- UEFI启动 安装win8 win10 及windows server 2012 最简单的方法
纯UEFI模式只认U盘 纯UEFI模式下U盘安装的具体步骤其实很简单: 1.BIOS设置中启动项关闭兼容模式 ...
- oracle 时区
select sysdate from dual;select systimestamp from dual;select localtimestamp from dual;select curren ...
- JAVA基础——设计模式之装饰者模式
装饰模式 : 对新房进行装修并没有改变房屋的本质,但它可以让房子变得更漂亮.更温馨.更实用. 在软件设计中,对已有对象(新房)的功能进行扩展(装修). 把通用功能封装在装饰器中,用到的地方 ...
- joda-time时间操作组件
今天看到了学习到了一个不错的操作时间的jar包,很方便的,以后操作时间运算就可以直接使用jar包中的方法了,再也不用自己写操作时间的方法了.懒的不行不行的 <!-- 时间操作组件 --> ...