\(\\\)

\(Description\)


有\(N\)头牛,\(F\)种食物,\(D\)种饮料,每种食物和饮料只有一份。

现在已知每头牛可以吃哪些食物,可以喝哪些饮料,问最多可以让多少头牛可以同时得到喜欢的食物和饮料。

  • \(N,F,D\in [1,100]\)

\(\\\)

\(Solution@\)二分图


这是一个最大匹配问题,但是需要两侧同时满足可以增广,有一侧不合法就不计入答案。

直接两侧分别做一次匈牙利是有问题的。如果一侧匹配上了,另一侧没有,那么其实在\(DFS\)的过程中已经将某一侧的匹配对象改变了,进而可能会导致下一步其他元素在匹配的时候匹配不上。

于是我们在每次增广之前先备份一份\(match\)数组,如果出现了一侧匹配一侧不匹配的情况就将\(match\)数组还原。

\(\\\)

\(Code\)


出锅了...\(Luogu\)上一道几乎一样的题交了就过了,但是这道题一直\(80\)。

下了一波数据发现好像是有的牛没有喜欢的食物和饮料的锅....

然后把这种情况算成合法又有一个点跪了...那个点里好像这种情况又不算做合法了...

还是没有想懂网络流为啥过了...网络流做似乎并没有将这种特殊点算作合法...大爷们找到原因麻烦告诉我一声...

  1. #include<cmath>
  2. #include<cstdio>
  3. #include<cctype>
  4. #include<cstdlib>
  5. #include<cstring>
  6. #include<iostream>
  7. #include<algorithm>
  8. #define N 110
  9. #define R register
  10. #define gc getchar
  11. using namespace std;
  12. inline int rd(){
  13. int x=0; bool f=0; char c=gc();
  14. while(!isdigit(c)){if(c=='-')f=1;c=gc();}
  15. while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
  16. return f?-x:x;
  17. }
  18. int n,f,d,ans,tot1,hd1[N],tot2,hd2[N];
  19. int m1[N],m2[N],vis1[N],vis2[N],tmp1[N],tmp2[N];
  20. struct edge{int to,nxt;}e1[N*N],e2[N*N];
  21. inline void add1(int u,int v){
  22. e1[++tot1].to=v; e1[tot1].nxt=hd1[u]; hd1[u]=tot1;
  23. }
  24. inline void add2(int u,int v){
  25. e2[++tot2].to=v; e2[tot2].nxt=hd2[u]; hd2[u]=tot2;
  26. }
  27. inline bool dfs1(int u,int t){
  28. for(R int i=hd1[u],v;i;i=e1[i].nxt)
  29. if(vis1[v=e1[i].to]!=t){
  30. vis1[v]=t;
  31. if(!m1[v]||dfs1(m1[v],t)){m1[v]=u;return 1;}
  32. }
  33. return 0;
  34. }
  35. inline bool dfs2(int u,int t){
  36. for(R int i=hd2[u],v;i;i=e2[i].nxt)
  37. if(vis2[v=e2[i].to]!=t){
  38. vis2[v]=t;
  39. if(!m2[v]||dfs2(m2[v],t)){m2[v]=u;return 1;}
  40. }
  41. return 0;
  42. }
  43. int main(){
  44. n=rd(); f=rd(); d=rd();
  45. for(R int i=1,x,y;i<=n;++i){
  46. x=rd(); y=rd();
  47. for(R int j=1,v;j<=x;++j){v=rd();add1(i,v);}
  48. for(R int j=1,v;j<=y;++j){v=rd();add2(i,v);}
  49. }
  50. for(R int i=1;i<=n;++i){
  51. for(R int j=1;j<=f;++j) tmp1[j]=m1[j];
  52. for(R int j=1;j<=d;++j) tmp2[j]=m2[j];
  53. if(dfs1(i,i)&&dfs2(i,i)) ++ans;
  54. else{
  55. for(R int j=1;j<=f;++j) m1[j]=tmp1[j];
  56. for(R int j=1;j<=d;++j) m2[j]=tmp2[j];
  57. }
  58. }
  59. printf("%d\n",ans);
  60. return 0;
  61. }

\(\\\)

\(Solution@\)网络流


这是一个最大流问题,考虑有两个限制同时满足才可以将一个点视为合法,所以建图考虑将限制分别放在牛的两侧,容量都为\(1\),这样答案就转化成了最大流。

有一种情况需要特殊考虑,如下图,最大流是\(3\),实际上答案是\(1\),因为忽视了每头牛的贡献最多为\(1\)的限制。

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

\(\\\)

\(Code\)


  1. #include<cmath>
  2. #include<queue>
  3. #include<cstdio>
  4. #include<cctype>
  5. #include<cstdlib>
  6. #include<cstring>
  7. #include<iostream>
  8. #include<algorithm>
  9. #define N 10100
  10. #define R register
  11. #define gc getchar
  12. #define inf 200000000
  13. using namespace std;
  14. inline int rd(){
  15. int x=0; bool f=0; char c=gc();
  16. while(!isdigit(c)){if(c=='-')f=1;c=gc();}
  17. while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
  18. return f?-x:x;
  19. }
  20. int n,m1,m2,cnt,f[N],l[N],r[N],c[N];
  21. int s,t,tot=1,hd[N],h[N],dp[N];
  22. struct edge{int w,to,nxt;}e[N*100];
  23. inline void add(int u,int v,int w){
  24. e[++tot].to=v; e[tot].w=w;
  25. e[tot].nxt=hd[u]; hd[u]=tot;
  26. }
  27. queue<int> q;
  28. inline bool bfs(){
  29. for(R int i=0;i<=cnt;++i) dp[i]=0;
  30. dp[s]=1; q.push(s);
  31. while(!q.empty()){
  32. int u=q.front(); q.pop();
  33. for(R int i=hd[u],v;i;i=e[i].nxt)
  34. if(e[i].w&&(!dp[v=e[i].to])){
  35. dp[v]=dp[u]+1; q.push(v);
  36. }
  37. }
  38. return dp[t]>0;
  39. }
  40. inline int dfs(int u,int flow){
  41. if(u==t||!flow) return flow;
  42. int res=0,tmp;
  43. for(R int &i=h[u];i;i=e[i].nxt)
  44. if(e[i].w&&(dp[e[i].to]==dp[u]+1)){
  45. tmp=dfs(e[i].to,min(e[i].w,flow-res));
  46. e[i].w-=tmp; e[i^1].w+=tmp; res+=tmp;
  47. if(res==flow) return res;
  48. }
  49. return res;
  50. }
  51. inline int dinic(){
  52. int res=0;
  53. while(bfs()){
  54. for(R int i=0;i<=cnt;++i) h[i]=hd[i];
  55. res+=dfs(s,inf);
  56. }
  57. return res;
  58. }
  59. int main(){
  60. n=rd(); m1=rd(); m2=rd();
  61. for(R int i=1;i<=m1;++i) f[i]=++cnt;
  62. for(R int i=1;i<=n;++i) l[i]=++cnt,r[i]=++cnt;
  63. for(R int i=1;i<=m2;++i) c[i]=++cnt;
  64. s=0; t=++cnt;
  65. for(R int i=1;i<=m1;++i){add(s,f[i],1);add(f[i],s,0);}
  66. for(R int i=1;i<=n;++i){add(l[i],r[i],1);add(r[i],l[i],0);}
  67. for(R int i=1;i<=m2;++i){add(c[i],t,1);add(t,c[i],0);}
  68. for(R int i=1,a,b,x;i<=n;++i){
  69. a=rd(); b=rd();
  70. for(R int j=1;j<=a;++j){
  71. x=rd(); add(f[x],l[i],1); add(l[i],f[x],0);
  72. }
  73. for(R int j=1;j<=b;++j){
  74. x=rd(); add(r[i],c[x],1); add(c[x],r[i],0);
  75. }
  76. }
  77. printf("%d\n",dinic());
  78. return 0;
  79. }

[ USACO 2007 OPEN ] Dining的更多相关文章

  1. 便宜的回文 (USACO 2007)(c++)

    2019-08-21便宜的回文(USACO 2007) 内存限制:128 MiB 时间限制:1000 ms 标准输入输出 题目类型:传统 评测方式:文本比较 题目描述 追踪每头奶牛的去向是一件棘手的任 ...

  2. 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 ...

  3. NC25025 [USACO 2007 Nov G]Sunscreen

    NC25025 [USACO 2007 Nov G]Sunscreen 题目 题目描述 To avoid unsightly burns while tanning, each of the \(C\ ...

  4. 【BZOJ】【1046】/【POJ】【3613】【USACO 2007 Nov】Cow Relays 奶牛接力跑

    倍增+Floyd 题解:http://www.cnblogs.com/lmnx/archive/2012/05/03/2481217.html 神题啊= =Floyd真是博大精深…… 题目大意为求S到 ...

  5. BZOJ 1631==USACO 2007== POJ 3268 Cow Party奶牛派对

    Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 19226   Accepted: 8775 Description One ...

  6. 【POJ3612】【USACO 2007 Nov Gold】 1.Telephone Wire 动态调节

    意甲冠军: 一些树高给出.行一种操作:把某棵树增高h,花费为h*h. 操作完毕后连线,两棵树间花费为高度差*定值c. 求两种花费加和最小值. 题解: 跟NOIP2014 D1T3非常像. 暴力动规是O ...

  7. [BZOJ 1647][USACO 2007 Open] Fliptile 翻格子游戏

    1647: [Usaco2007 Open]Fliptile 翻格子游戏 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 702  Solved: 281[ ...

  8. [ USACO 2007 FEB ] Lilypad Pond (Silver)

    \(\\\) \(Description\) 一张\(N\times M\)的网格,已知起点和终点,其中有一些地方是落脚点,有一些地方是空地,还有一些地方是坏点. 现在要从起点到终点,每次移动走日字\ ...

  9. [ USACO 2007 FEB ] Lilypad Pond (Gold)

    \(\\\) \(Description\) 一张\(N\times M\)的网格,已知起点和终点,其中有一些地方是落脚点,有一些地方是空地,还有一些地方是坏点. 现在要从起点到终点,每次移动走日字\ ...

随机推荐

  1. 【13】AngularJS 模块

    AngularJS 模块 模块定义了一个应用程序.(魔芋:也就是说一个ng-app代表一个应用程序,也就是一个模块,module) 模块是应用程序中不同部分的容器. 模块是应用控制器的容器. 控制器通 ...

  2. HDU 2082 母函数法

    #include <cstdio> #include <cstring> using namespace std; ] , dp[][]; int main() { // fr ...

  3. ORA_ROWSCN

    这是一个非常重要的特性.从oracle10g开始,oracle在表上引入了一个伪列ORA_ROWSCN.该列记录了每一列最后更改的SCN.但是有两种模式,一种是默认的是data block级别,另一种 ...

  4. hp 1810-24g switch reset

    Specific steps to execute the factory default reset on the switch are: 1. Using a small, thin tool w ...

  5. PKU 3667 Hotel (线段树,区间合并,最长连续区间)

    题意:宾馆有N个房间(1~N),M个操作,a=1,输入b,表示N间房是否有连续的b间房.有输出最左边的房编号 没有输出0.a=2,输入b,c表示房间b到c清空. 模仿了大神的代码,敲了一遍,有些地方还 ...

  6. 关于C语言指针的一些新认识(1)

    Technorati 标签: 指针,数组,汇编,C语言 前言 指针是C语言的精华,但我对它一直有种敬而远之的感觉,因为一个不小心就可能让你的程序陷入莫名其妙的麻烦之中.所以,在处理字符串时,我总是能用 ...

  7. Java课程设计——人事管理系统

    主界面代码: package PersonSystem; import java.awt.*; import java.awt.event.*; import javax.swing.*; impor ...

  8. mac 浏览器解决跨域问题

    Chrome:命令行执行如下命令open -a Google\ Chrome --args --disable-web-security出现如下提示,说明已经开启: Safari: open -a ' ...

  9. Android资源之图像资源(图像级别资源)

    图像状态资源仅仅能定义有限的几种状态. 假设须要很多其它的状态,就要使用图像级别资源. 在该资源文件里能够定义随意多个图像级别. 每一个图像级别是一个整数区间,能够通过ImageView.setIma ...

  10. Android Application Digital Signatures - Android 数字签名

    Android 数字签名 同一个开发人员的多个程序尽可能使用同一个数字证书,这能够带来下面优点. (1)有利于程序升级,当新版程序和旧版程序的数字证书同样时,Android系统才会觉得这两个程序是同一 ...