P1402 酒店之王[网络瘤(正解)/匈牙利(错解)]
题目描述
XX酒店的老板想成为酒店之王,本着这种希望,第一步要将酒店变得人性化。由于很多来住店的旅客有自己喜好的房间色调、阳光等,也有自己所爱的菜,但是该酒店只有p间房间,一天只有固定的q道不同的菜。
有一天来了n个客人,每个客人说出了自己喜欢哪些房间,喜欢哪道菜。但是很不幸,可能做不到让所有顾客满意(满意的条件是住进喜欢的房间,吃到喜欢的菜)。
这里要怎么分配,能使最多顾客满意呢?
解析
学了匈牙利,还是讲一个匈牙利的做法。
先说一点,目前并没有找到匈牙利二分图匹配做法完全正确的例子。
分析一下思路问题。
最开始我的思路是直接匹配房和菜,交上去只有40分,仔细思考发现这样一个细节:如果直接匹配房菜,实际上可以把匹配边抽象成一个人,那么在匈牙利找出一条增广路时,会把之前配对的房菜弃用,通俗的讲就是这对房菜其中一个再也不会被这个人使用,然鹅我们并不具体知道是哪一个,而且对于把边抽象成人这个说法又不太准确,毕竟有可能边连的比人还多。而真实情况是,这个人既有可能换房,也有可能换菜,我们要分别考虑。能对4个点已经很不错了。
所以,我们需要建两个图,把人记下来当作未匹配点,分别对菜、人和人、房同步进行二分图匹配。同步即,此时进行增广的起始点为同一个人。这样依次对所有人进行增广,跑一遍匈牙利算法,就可得出最大匹配。
但
这样还是错的,我就很纳闷,仔细一想,发现问题还是出现在相似的地方。两边同步进行二分图匹配时,我们需要考虑更多。我们发现当一个人无法进行增广时,他有可能是在其中一张图上无法增广,有可能在两张图上都无法增广。显然如果其中一张图无法增广,另一张图如果你还增广,就相当于这个人只选了一个东西,或者菜或者房,那显然不符合题目要求。所以我们索性就不管这个人了,直接跳过这个人不增广他,继续往后面的人增广。
如果这么写的话,是可以A这道题的,但是依然有人hack掉了。
至于被hack的原因,补充一点个人想法:
注意到上面提到的跳过无法增广的人的思路,实际上细想还是存在问题。试想,是否存在一种情况,我们选择了这个本应被跳过的人,然后挤掉了之前的某个人,会使得整体更优?按道理来讲我觉得是存在的,也就是说这种做法是有后效性的,或许某种后面的决策会影响到之前的决策,并且还会使整体更优?那么如果这样讲,匈牙利是做不了这题的,匈牙利算法本身就无法胜任(毕竟哪也没写它可以同时处理两张有交叉的二分图)。
仅个人理解,如有错误,望dalao指正。
参考代码
这回就真的只是参考了,能AC,但是不一定完全正确。
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<ctime>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<bitset>
#define N 501
using namespace std;
inline int read()
{
int f=1,x=0;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
int a[N][N],b[N][N],n,p,q,f1[N],f2[N],res1[N],res2[N];
vector<int> g1[N],g2[N];
bitset<N> v1,v2;
inline bool dfs1(int x)//正宗二分图匹配
{
for(register int i=0;i<g1[x].size();++i){
int y=g1[x][i];
if(v1[y]) continue;
v1[y]=1;
if(!f1[y]||dfs1(f1[y])){
f1[y]=x;
return 1;
}
}
return 0;
}
inline bool dfs2(int x)
{
for(register int i=0;i<g2[x].size();++i){
int y=g2[x][i];
if(v2[y]) continue;
v2[y]=1;
if(!f2[y]||dfs2(f2[y])){
f2[y]=x;
return 1;
}
}
return 0;
}
int main()
{
n=read(),p=read(),q=read();
for(int i=1;i<=n;++i)
for(int j=1;j<=p;++j) scanf("%d",&a[i][j]);
for(int i=1;i<=n;++i)
for(int j=1;j<=q;++j) scanf("%d",&b[i][j]);
for(int i=1;i<=n;++i)
for(int j=1;j<=p;++j)
for(int k=1;k<=q;++k)
//建图,这边我建图稍微麻烦了点,但是比较好理解
if(a[i][j]) g1[i].push_back(j+n),g1[j+n].push_back(i);
else if(b[i][k]) g2[i].push_back(k+n),g2[k+n].push_back(i);
int ans=0;
for(int i=1;i<=n;++i){
v1.reset(),v2.reset();
memcpy(res1,f1,sizeof(f1));
memcpy(res2,f2,sizeof(f2));
if(dfs1(i)&&dfs2(i)) ans++;
else{
memcpy(f1,res1,sizeof(f1));//回溯过程
memcpy(f2,res2,sizeof(f2));
}
}
cout<<ans<<endl;
return 0;
}
P1402 酒店之王[网络瘤(正解)/匈牙利(错解)]的更多相关文章
- P1402 酒店之王【网络流】【最大流】
P1402 酒店之王 提交 5.39k 通过 2.16k 时间限制 1.00s 内存限制 125.00MB 题目提供者yeszy 难度省选/NOI- 历史分数100 提交记录 查看题解 标签 福建省历 ...
- 洛谷P2891 Dining P1402 酒店之王【类二分图匹配】题解+代码
洛谷P2891 Dining P1402 酒店之王[类二分图匹配]题解+代码 酒店之王 题目描述 XX酒店的老板想成为酒店之王,本着这种希望,第一步要将酒店变得人性化.由于很多来住店的旅客有自己喜好的 ...
- P1402 酒店之王
P1402 酒店之王 每个人要匹配一个A和一个B,所以这样连边: S向每个房间连边. 每个房间向喜欢这个房间的人连边. 每个人向喜欢的菜连边. 每道菜向T连边. 边权均为1. 注意人要限流. // I ...
- 洛谷P1402 酒店之王(二分图)
P1402 酒店之王 题目描述 XX酒店的老板想成为酒店之王,本着这种希望,第一步要将酒店变得人性化.由于很多来住店的旅客有自己喜好的房间色调.阳光等,也有自己所爱的菜,但是该酒店只有p间房间,一天只 ...
- 【刷题】洛谷 P1402 酒店之王
题目描述 XX酒店的老板想成为酒店之王,本着这种希望,第一步要将酒店变得人性化.由于很多来住店的旅客有自己喜好的房间色调.阳光等,也有自己所爱的菜,但是该酒店只有p间房间,一天只有固定的q道不同的菜. ...
- P1402 酒店之王 最大流
\(\color{#0066ff}{ 题目描述 }\) XX酒店的老板想成为酒店之王,本着这种希望,第一步要将酒店变得人性化.由于很多来住店的旅客有自己喜好的房间色调.阳光等,也有自己所爱的菜,但是该 ...
- luogu P1402 酒店之王
题目描述 XX酒店的老板想成为酒店之王,本着这种希望,第一步要将酒店变得人性化.由于很多来住店的旅客有自己喜好的房间色调.阳光等,也有自己所爱的菜,但是该酒店只有p间房间,一天只有固定的q道不同的菜. ...
- BZOJ 1711 吃饭dining/Luogu P1402 酒店之王 拆点+最大流流匹配
题意: (吃饭dining)有F种食物和D种饮料,每种食物或饮料只能供一头牛享用,且每头牛只享用一种食物和一种饮料.现在有n头牛,每头牛都有自己喜欢的食物种类列表和饮料种类列表,问最多能使几头牛同时享 ...
- P1402 酒店之王 网络流
大水题,我自己瞎做就做出来了,没啥说的,zz建图,就是板子. 题干: 题目描述 XX酒店的老板想成为酒店之王,本着这种希望,第一步要将酒店变得人性化.由于很多来住店的旅客有自己喜好的房间色调.阳光等, ...
随机推荐
- Influx Sql系列教程一:database 数据库
对于influxdb而言,database和我们更熟悉的mysql中的dababse没有什么特别的区别,可以将数据库简单理解为一堆表(measurement)的集合,接下来我们将看一下在influxd ...
- linux awk的用法
linux awk的用法 <pre>[root@iZ23uewresmZ ~]# cat /home/ceshis.txtb 12 42 30 b 03 43 25 a 08 10 16 ...
- Cookie 允许第三方cookie
这样本地调线上的接口,就可以使用线上接口生成的cookie了. 或者允许,或者增加白名单.
- 总结IDEA和VS常用实用的快捷键
整理了我一般撸码时使用下面两个IDE最常用到的快捷键: IntelliJ IDEA: 快捷搜索:Ctrl+F (Match Case:区分大小写,Words:全字匹配,Regex:正则匹配) 批量替换 ...
- Tomcat是一个Servlet容器?
"Tomcat是一个Servlet容器",这句话对于2019年的程序员应该是耳熟能详的. 单纯的思考一下这句话,我们可以抽象出来这么一段代码: class Tomcat { Lis ...
- Java开发笔记(一百三十八)JavaFX的箱子
前面介绍了JavaFX标签控件的用法,其中提到Label文本支持中文字体,那么它到底支持哪些中文字体呢?自然要看当前的操作系统都安装了哪些字体才行,对于中文的Windows系统,默认安装了黑体“Sim ...
- noip2019集训测试赛(二十一)Problem A: Colorful Balls
Problem A: Colorful Balls Description Snuke放了N个一排彩色的球.从左起第i个球的颜色是ci重量是wi她可以通过执行两种操作对这些球重新排序操作1:选择两个相 ...
- python列表生成式、键盘输入及类型转换、字符串翻转、字母大小写、数组广播、循环语句等基础问题
Python知识总结 1.列表生成式 在实际开发过程中,当需要获取一个连续列表时,可直接使用range(3,10),但是如果获取该列表中每个数据的平方时,通常可以通过for循环来解决这个问题,如下 ...
- Linux中的两个经典宏定义:获取结构体成员地址,根据成员地址获得结构体地址;Linux中双向链表的经典实现。
倘若你查看过Linux Kernel的源码,那么你对 offsetof 和 container_of 这两个宏应该不陌生.这两个宏最初是极客写出的,后来在Linux内核中被推广使用. 1. offse ...
- PHP网文
1.php底层运行机制及原理 https://cloud.tencent.com/developer/article/1055801