zoukankan      html  css  js  c++  java
  • POJ 1149(最大流)

    这道题应该都能想到朴素的有n*m+个点的建图方案吧,呵呵,显然是不行的。

    那么怎么办?

    其实我们可以这样想:一个人能买到的猪有两个来源:

    ①来自自己第一次打开的猪圈

    ②来自之前别人打开的猪圈

    想到了这个实质,见图就简单了!

    我们设一个超级源点S,和超级汇点T,对于每一个人,从S向他连一条容量为K的边(K是由这个人第一次打开的猪圈的初始猪的个数之和),然后对于一个人A,他打开了P猪圈,

    且P猪圈之前被B打开过,则从B向A连一条容量为INF的边,最后,对于每一个人,都向T连一条容量为lim[i](表示每个人的购买猪的上限)的边,跑在最大流就行!

    代码:

    View Code
     1 #include <cstdio>
     2 #include <cstdlib>
     3 #include <cstring>
     4 #include <iostream>
     5 #define N 2010
     6 #define M  200100
     7 #define INF 100000000
     8 using namespace std;
     9 int head[N],next[M],to[M],len[M],cnt,S,T,n,m,layer[N],q[M<<4]; 
    10 int cus[N],ini[N],num[N],key[N][N],lim[N],ww[N];
    11 inline void add(int u,int v,int w)
    12 {
    13     to[cnt]=v; len[cnt]=w; next[cnt]=head[u]; head[u]=cnt++;
    14     to[cnt]=u; len[cnt]=0; next[cnt]=head[v]; head[v]=cnt++;
    15 }
    16 void read()
    17 {
    18     memset(cus,0,sizeof cus);
    19     memset(ww,0,sizeof ww);
    20     memset(head,-1,sizeof head);
    21     cnt=0;
    22     S=0; T=n+1;
    23     for(int i=1;i<=m;i++) scanf("%d",&ini[i]);
    24     for(int i=1;i<=n;i++)
    25     {
    26         scanf("%d",&num[i]);
    27         for(int j=1;j<=num[i];j++)
    28         {
    29             scanf("%d",&key[i][j]);
    30             //cus[i]表示上一次开启i猪圈的人的编号 
    31             if(cus[key[i][j]]==0)//i是第一个开key[i][j]猪圈的人
    32             { 
    33                 ww[i]+=ini[key[i][j]];
    34                 cus[key[i][j]]=i;//更新 
    35             }
    36             else
    37             {
    38                 add(cus[key[i][j]],i,INF);
    39                 cus[key[i][j]]=i;
    40             }
    41         }
    42         scanf("%d",&lim[i]);
    43     }
    44     for(int i=1;i<=n;i++) add(S,i,ww[i]),add(i,T,lim[i]);
    45 }
    46 bool bfs()
    47 {
    48     memset(layer,-1,sizeof layer);
    49     int h=1,t=2,sta;
    50     q[1]=S; layer[S]=0;
    51     while(h<t)
    52     {
    53         sta=q[h++];
    54         for(int i=head[sta];~i;i=next[i])
    55             if(len[i]>0&&layer[to[i]]<0)
    56             {
    57                 layer[to[i]]=layer[sta]+1;
    58                 q[t++]=to[i];
    59             }
    60     }
    61     return layer[T]!=-1;
    62 }
    63 int find(int u,int cur_flow)
    64 {
    65     if(u==T) return cur_flow;
    66     int result=0,tmp;
    67     for(int i=head[u];~i&&result<cur_flow;i=next[i])
    68         if(len[i]>0&&layer[to[i]]==layer[u]+1)
    69         {
    70             tmp=find(to[i],min(cur_flow-result,len[i]));
    71             len[i]-=tmp; len[i^1]+=tmp; result+=tmp;
    72         }
    73     if(!result) layer[u]=-1;
    74     return result;
    75 }
    76 int dinic()
    77 {
    78     int ans=0;
    79     while(bfs()) ans+=find(S,INF);
    80     return ans;
    81 }
    82 int main()
    83 {
    84     while(scanf("%d%d",&m,&n)!=EOF)
    85     {
    86         read();
    87         printf("%d\n",dinic());
    88     }
    89     return 0;
    90 }
    没有人能阻止我前进的步伐,除了我自己!
  • 相关阅读:
    layer 弹出层 回调函数调用 弹出层页面 函数
    jquery 封装页面之间获取值
    ZTree 获取选中的项
    动态拼接SQL 语句
    翻译-使用Spring调用SOAP Web Service
    分享最新的博客到LinkedIn Timeline
    翻译-使用Spring WebService生成SOAP Web Service
    在Gradle中使用jaxb的xjc插件
    Gradle中的buildScript代码块
    健身4个月总结
  • 原文地址:https://www.cnblogs.com/proverbs/p/2659317.html
Copyright © 2011-2022 走看看