[ USACO 2007 OPEN ] Dining
\(\\\)
\(Description\)
有\(N\)头牛,\(F\)种食物,\(D\)种饮料,每种食物和饮料只有一份。
现在已知每头牛可以吃哪些食物,可以喝哪些饮料,问最多可以让多少头牛可以同时得到喜欢的食物和饮料。
- \(N,F,D\in [1,100]\)
\(\\\)
\(Solution@\)二分图
这是一个最大匹配问题,但是需要两侧同时满足可以增广,有一侧不合法就不计入答案。
直接两侧分别做一次匈牙利是有问题的。如果一侧匹配上了,另一侧没有,那么其实在\(DFS\)的过程中已经将某一侧的匹配对象改变了,进而可能会导致下一步其他元素在匹配的时候匹配不上。
于是我们在每次增广之前先备份一份\(match\)数组,如果出现了一侧匹配一侧不匹配的情况就将\(match\)数组还原。
\(\\\)
\(Code\)
出锅了...\(Luogu\)上一道几乎一样的题交了就过了,但是这道题一直\(80\)。
下了一波数据发现好像是有的牛没有喜欢的食物和饮料的锅....
然后把这种情况算成合法又有一个点跪了...那个点里好像这种情况又不算做合法了...
还是没有想懂网络流为啥过了...网络流做似乎并没有将这种特殊点算作合法...大爷们找到原因麻烦告诉我一声...
#include<cmath>
#include<cstdio>
#include<cctype>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 110
#define R register
#define gc getchar
using namespace std;
inline int rd(){
int x=0; bool f=0; char c=gc();
while(!isdigit(c)){if(c=='-')f=1;c=gc();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
return f?-x:x;
}
int n,f,d,ans,tot1,hd1[N],tot2,hd2[N];
int m1[N],m2[N],vis1[N],vis2[N],tmp1[N],tmp2[N];
struct edge{int to,nxt;}e1[N*N],e2[N*N];
inline void add1(int u,int v){
e1[++tot1].to=v; e1[tot1].nxt=hd1[u]; hd1[u]=tot1;
}
inline void add2(int u,int v){
e2[++tot2].to=v; e2[tot2].nxt=hd2[u]; hd2[u]=tot2;
}
inline bool dfs1(int u,int t){
for(R int i=hd1[u],v;i;i=e1[i].nxt)
if(vis1[v=e1[i].to]!=t){
vis1[v]=t;
if(!m1[v]||dfs1(m1[v],t)){m1[v]=u;return 1;}
}
return 0;
}
inline bool dfs2(int u,int t){
for(R int i=hd2[u],v;i;i=e2[i].nxt)
if(vis2[v=e2[i].to]!=t){
vis2[v]=t;
if(!m2[v]||dfs2(m2[v],t)){m2[v]=u;return 1;}
}
return 0;
}
int main(){
n=rd(); f=rd(); d=rd();
for(R int i=1,x,y;i<=n;++i){
x=rd(); y=rd();
for(R int j=1,v;j<=x;++j){v=rd();add1(i,v);}
for(R int j=1,v;j<=y;++j){v=rd();add2(i,v);}
}
for(R int i=1;i<=n;++i){
for(R int j=1;j<=f;++j) tmp1[j]=m1[j];
for(R int j=1;j<=d;++j) tmp2[j]=m2[j];
if(dfs1(i,i)&&dfs2(i,i)) ++ans;
else{
for(R int j=1;j<=f;++j) m1[j]=tmp1[j];
for(R int j=1;j<=d;++j) m2[j]=tmp2[j];
}
}
printf("%d\n",ans);
return 0;
}
\(\\\)
\(Solution@\)网络流
这是一个最大流问题,考虑有两个限制同时满足才可以将一个点视为合法,所以建图考虑将限制分别放在牛的两侧,容量都为\(1\),这样答案就转化成了最大流。
有一种情况需要特殊考虑,如下图,最大流是\(3\),实际上答案是\(1\),因为忽视了每头牛的贡献最多为\(1\)的限制。

于是有一个机智的做法,将每一个牛都拆成两个点,连一条容量为\(1\)的边,这样每个牛最多只会允许一支流通过。

\(\\\)
\(Code\)
#include<cmath>
#include<queue>
#include<cstdio>
#include<cctype>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 10100
#define R register
#define gc getchar
#define inf 200000000
using namespace std;
inline int rd(){
int x=0; bool f=0; char c=gc();
while(!isdigit(c)){if(c=='-')f=1;c=gc();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
return f?-x:x;
}
int n,m1,m2,cnt,f[N],l[N],r[N],c[N];
int s,t,tot=1,hd[N],h[N],dp[N];
struct edge{int w,to,nxt;}e[N*100];
inline void add(int u,int v,int w){
e[++tot].to=v; e[tot].w=w;
e[tot].nxt=hd[u]; hd[u]=tot;
}
queue<int> q;
inline bool bfs(){
for(R int i=0;i<=cnt;++i) dp[i]=0;
dp[s]=1; q.push(s);
while(!q.empty()){
int u=q.front(); q.pop();
for(R int i=hd[u],v;i;i=e[i].nxt)
if(e[i].w&&(!dp[v=e[i].to])){
dp[v]=dp[u]+1; q.push(v);
}
}
return dp[t]>0;
}
inline int dfs(int u,int flow){
if(u==t||!flow) return flow;
int res=0,tmp;
for(R int &i=h[u];i;i=e[i].nxt)
if(e[i].w&&(dp[e[i].to]==dp[u]+1)){
tmp=dfs(e[i].to,min(e[i].w,flow-res));
e[i].w-=tmp; e[i^1].w+=tmp; res+=tmp;
if(res==flow) return res;
}
return res;
}
inline int dinic(){
int res=0;
while(bfs()){
for(R int i=0;i<=cnt;++i) h[i]=hd[i];
res+=dfs(s,inf);
}
return res;
}
int main(){
n=rd(); m1=rd(); m2=rd();
for(R int i=1;i<=m1;++i) f[i]=++cnt;
for(R int i=1;i<=n;++i) l[i]=++cnt,r[i]=++cnt;
for(R int i=1;i<=m2;++i) c[i]=++cnt;
s=0; t=++cnt;
for(R int i=1;i<=m1;++i){add(s,f[i],1);add(f[i],s,0);}
for(R int i=1;i<=n;++i){add(l[i],r[i],1);add(r[i],l[i],0);}
for(R int i=1;i<=m2;++i){add(c[i],t,1);add(t,c[i],0);}
for(R int i=1,a,b,x;i<=n;++i){
a=rd(); b=rd();
for(R int j=1;j<=a;++j){
x=rd(); add(f[x],l[i],1); add(l[i],f[x],0);
}
for(R int j=1;j<=b;++j){
x=rd(); add(r[i],c[x],1); add(c[x],r[i],0);
}
}
printf("%d\n",dinic());
return 0;
}
[ USACO 2007 OPEN ] Dining的更多相关文章
- 便宜的回文 (USACO 2007)(c++)
2019-08-21便宜的回文(USACO 2007) 内存限制:128 MiB 时间限制:1000 ms 标准输入输出 题目类型:传统 评测方式:文本比较 题目描述 追踪每头奶牛的去向是一件棘手的任 ...
- NC25043 [USACO 2007 Jan S]Protecting the Flowers
NC25043 [USACO 2007 Jan S]Protecting the Flowers 题目 题目描述 Farmer John went to cut some wood and left ...
- NC25025 [USACO 2007 Nov G]Sunscreen
NC25025 [USACO 2007 Nov G]Sunscreen 题目 题目描述 To avoid unsightly burns while tanning, each of the \(C\ ...
- 【BZOJ】【1046】/【POJ】【3613】【USACO 2007 Nov】Cow Relays 奶牛接力跑
倍增+Floyd 题解:http://www.cnblogs.com/lmnx/archive/2012/05/03/2481217.html 神题啊= =Floyd真是博大精深…… 题目大意为求S到 ...
- BZOJ 1631==USACO 2007== POJ 3268 Cow Party奶牛派对
Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 19226 Accepted: 8775 Description One ...
- 【POJ3612】【USACO 2007 Nov Gold】 1.Telephone Wire 动态调节
意甲冠军: 一些树高给出.行一种操作:把某棵树增高h,花费为h*h. 操作完毕后连线,两棵树间花费为高度差*定值c. 求两种花费加和最小值. 题解: 跟NOIP2014 D1T3非常像. 暴力动规是O ...
- [BZOJ 1647][USACO 2007 Open] Fliptile 翻格子游戏
1647: [Usaco2007 Open]Fliptile 翻格子游戏 Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 702 Solved: 281[ ...
- [ USACO 2007 FEB ] Lilypad Pond (Silver)
\(\\\) \(Description\) 一张\(N\times M\)的网格,已知起点和终点,其中有一些地方是落脚点,有一些地方是空地,还有一些地方是坏点. 现在要从起点到终点,每次移动走日字\ ...
- [ USACO 2007 FEB ] Lilypad Pond (Gold)
\(\\\) \(Description\) 一张\(N\times M\)的网格,已知起点和终点,其中有一些地方是落脚点,有一些地方是空地,还有一些地方是坏点. 现在要从起点到终点,每次移动走日字\ ...
随机推荐
- poj 2823 二分法+单调队列
#include<stdio.h> #include<string.h> #define N 1100000 int a[N]; int fmin[N],fmax[N]; i ...
- ORA-12541:TNS:无监听程序
安装oracle以后,sql plus可以正常登陆,pl/sql登陆时报错ORA-12541:TNS:无监听程序,解决方案如下: http://blog.csdn.net/hao134838/arti ...
- Eclipse导入Ant项目
导入Ant项目有以下方式: 1.[File]->[Project]->[Java Project from Existing Ant Buildfile] 选择build.xml文件即可, ...
- Android 学习历程摘要(三)
1.proguard混淆:对与Activity等不应进行混淆.否则系统将找不到生命周期函数:JSON字符串要考虑混淆之后是否会影响字段名:native方法也不混淆,否则调用不到 2.ListView的 ...
- php 生成订单号
最近在练手一个订单提交的小项目,需要用到生成订单号,网上找了下,觉得这个最好. function build_order_no(){ return date('Ymd').substr(implode ...
- LeetCode 917. Reverse Only Letters (仅仅反转字母)
题目标签:String 利用left, right 两个pointers, 从左右开始 互换 字母.如果遇到的不是字母,那么继续移动到下一个. Java Solution: Runtime beats ...
- 【Unity 3D】学习笔记三十六:物理引擎——刚体
物理引擎就是游戏中模拟真是的物理效果.如两个物体发生碰撞,物体自由落体等.在unity中使用的是NVIDIA的physX,它渲染的游戏画面很逼真. 刚体 刚体是一个很很中要的组件. 默认情况下,新创的 ...
- c++ 编译器会绕过拷贝构造函数
C++ primer P442 P447:在拷贝初始化过程中,编译器可以跳过拷贝构造函数,直接创建对象.即,编译器允许将下面的代码 "; //1 改写为 "); //2 由于str ...
- System.load 与 System.loadLibrary 的区别
相同点 它们都可以用来装载库文件,不论是JNI库文件还是非JNI库文件. 在任何本地方法被调用之前必须先用这个两个方法之一把相应的JNI库文件装载. System.load System.load 参 ...
- 51nod 1611 金牌赛事
被亮亮D飞啦!!QWQ 这题明明是最大权闭合子图+线段树优化构图好不好 被迫考虑DP,并且考虑f[i]表示到第i个位置的最大值(第i个位置可选可不选) 对于最终的答案,我们可以分割成一段一段的,也就是 ...