zoukankan      html  css  js  c++  java
  • bzoj 1711 [Usaco2007 Open]Dining吃饭&&poj 3281 Dining

    最大流。

    这东西好像叫三分图匹配。

    源点向每个食物点连一条容量为1的边。

    每个饮料点向汇点连一条容量为1的边。

    将每个牛点拆点,食物点向喜欢它的牛的入点连一条容量为1的边,牛的出点向它喜欢的饮料点连一条容量为1的边。

    最大流即为答案,每头牛拆点是为了保证每头牛只有一种食物和一种饮料。

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #include<algorithm>
     5 #include<queue>
     6 using namespace std;
     7 const int dian=505;
     8 const int bian=50005;
     9 const int INF=0x3f3f3f3f;
    10 int h[dian],ver[bian],val[bian],nxt[bian],ch[dian],cr[dian];
    11 int n,m,k,tot,aa,bb,cc;
    12 int S,T;
    13 void add(int a,int b,int c){
    14     tot++;ver[tot]=b;val[tot]=c;nxt[tot]=h[a];h[a]=tot;
    15     tot++;ver[tot]=a;val[tot]=0;nxt[tot]=h[b];h[b]=tot;
    16 }
    17 bool tell(){
    18     memset(ch,-1,sizeof(ch));
    19     queue<int>q;
    20     q.push(S);
    21     ch[S]=0;
    22     while(!q.empty()){
    23         int t=q.front();
    24         q.pop();
    25         for(int i=h[t];i;i=nxt[i])
    26             if(ch[ver[i]]==-1&&val[i]){
    27                 ch[ver[i]]=ch[t]+1;
    28                 q.push(ver[i]);
    29             }
    30     }
    31     return ch[T]!=-1;
    32 }
    33 int zeng(int a,int b){
    34     if(a==T)
    35         return b;
    36     int r=0;
    37     for(int i=cr[a];i&&b>r;i=nxt[i])
    38         if(ch[ver[i]]==ch[a]+1&&val[i]){
    39             int t=zeng(ver[i],min(b-r,val[i]));
    40             val[i]-=t,r+=t,val[i^1]+=t;
    41             if(val[i])
    42                 cr[a]=i;
    43         }
    44     if(!r)
    45         ch[a]=-1;
    46     return r;
    47 }
    48 int dinic(){
    49     int r=0,t;
    50     while(tell()){
    51         for(int i=1;i<=n+n+m+k+2;i++)
    52             cr[i]=h[i];
    53         while(t=zeng(S,INF))
    54             r+=t;
    55     }
    56     return r;
    57 }
    58 int main(){
    59     memset(h,0,sizeof(h));
    60     memset(nxt,0,sizeof(nxt));
    61     tot=1;
    62     scanf("%d%d%d",&n,&m,&k);
    63     S=n+n+m+k+1,T=n+n+m+k+2;
    64     for(int i=1;i<=m;i++)
    65         add(S,i,1);
    66     for(int i=1;i<=k;i++)
    67         add(m+n+n+i,T,1);
    68     for(int i=1;i<=n;i++)
    69         add(m+i,m+n+i,1);
    70     for(int i=1;i<=n;i++){
    71         scanf("%d%d",&aa,&bb);
    72         for(int j=1;j<=aa;j++){
    73             scanf("%d",&cc);
    74             add(cc,m+i,1);
    75         }
    76         for(int j=1;j<=bb;j++){
    77             scanf("%d",&cc);
    78             add(m+n+i,m+n+n+cc,1);
    79         }
    80     }
    81     printf("%d",dinic());
    82     return 0;
    83 }

    另,做这道题是因为今天考了一场试,网络流专题。

    大爷看我们太弱没敢出太难,然后时间减了点,四个小时。

    然后我脑残没打输入输出文件,爆零了。

    赶紧打上,打上之后呢,还是爆零了。

    其实就是一道都不会。

    ……

    ……

    ……

    其实第一题不是很难,大概就是本题的加强版。

    给一个n*m的矩形,有一些坏点,所有i行j列的非坏点,若i+j为偶数,则该点封印着一个恶魔。其他非坏点可以放置一个魔法水晶,魔法水晶能向且只能向相邻的一个点施法。对于一个恶魔,如果与它相邻的两个成直角的水晶同时向它施法,他就无法逃脱封印。问最多让多少恶魔无法逃脱封印。

    1<=n,m<=50.

    边想边写搞了两个小时,当我发现我的第六个建图是错的的时候,我就放弃了整场考试。

    这题转化一下就是刚才的模型了。

    考虑成直角的充要条件是左右中选一个,上下中选一个。所以就是对于一个恶魔点,总要选一个奇数行(列)的点和一个偶数行(列)的点。

    这不就是食物和饮料嘛,源点连奇行点,偶行点连汇点,中间拆点然后相邻点连边,最大流完事。

    主要就是要看出点间这种二分图关系。

  • 相关阅读:
    Excel与Access的互作
    ThinkPHP第三天(公共函数Common加载,dump定义,模板文件,定义替换__PUBLIC__)
    ThinkPHP第四天(U函数,URL类型参数配置,伪静态后缀名配置,数据传递与获取$_GET等)
    ThinkPHP第六天(正则表达式)
    PHP函数积累
    bootstrap基础知识点YI
    集合中的方法
    hashable与unhashable
    集合的特点
    元组
  • 原文地址:https://www.cnblogs.com/dugudashen/p/6253305.html
Copyright © 2011-2022 走看看