zoukankan      html  css  js  c++  java
  • hdu 4292 拆点+简单网络流

    这题拆点一开始没想明白。

    原本的思路是 源点与食物相连,食物与人相连,人与饮料相连,饮料与汇点相连。。

    这样就貌似做到了最大流的求法了,但是这样就会出现一个问题,同一个牛可以选择多次的问题,因此需要给每头牛给上一个容量为1的限制条件,那就是拆点啦!~

    代码:

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #define MAXN 815
    #define INF 1e8
    #define min(a,b) (a<b?a:b)
    #define max(a,b) (a>b?a:b)
    using namespace std;
    struct edge
    {
        int u,v,w,next;
    }E[200000];
    int head[MAXN],ecnt;
    int gap[MAXN],cur[MAXN],pre[MAXN],dis[MAXN];
    int l,r,mid;
    int N,M,scr,sink,vn,num;
    int k,c1,m;
    void Insert(int u,int v,int w)
    {
        E[ecnt].u=u;
        E[ecnt].v=v;
        E[ecnt].w=w;
        E[ecnt].next=head[u];
        head[u]=ecnt++;
        E[ecnt].u=v;
        E[ecnt].v=u;
        E[ecnt].w=0;
        E[ecnt].next=head[v];
        head[v]=ecnt++;
    }
    int Sap(int s,int t,int n)//核心代码(模版)
    {
        int ans=0,aug=INF;//aug表示增广路的流量
        int i,v,u=pre[s]=s;
        for(i=0;i<=n;i++)
        {
            cur[i]=head[i];
            dis[i]=gap[i]=0;
        }
        gap[s]=n;
        bool flag;
        while(dis[s]<n)
        {
            flag=false;
            for(int &j=cur[u];j!=-1;j=E[j].next)//一定要定义成int &j,why
            {
                v=E[j].v;
                if(E[j].w>0&&dis[u]==dis[v]+1)
                {
                    flag=true;//找到容许边
                    aug=min(aug,E[j].w);
                    pre[v]=u;
                    u=v;
                    if(u==t)
                    {
                        ans+=aug;
                        while(u!=s)
                        {
                            u=pre[u];
                            E[cur[u]].w-=aug;
                            E[cur[u]^1].w+=aug;//注意
                        }
                        aug=INF;
                    }
                    break;//找到一条就退出
                }
            }
            if(flag) continue;
            int mindis=n;
            for(i=head[u];i!=-1;i=E[i].next)
            {
                v=E[i].v;
                if(E[i].w>0&&dis[v]<mindis)
                {
                    mindis=dis[v];
                    cur[u]=i;
                }
            }
            if((--gap[dis[u]])==0) break;
            gap[dis[u]=mindis+1]++;
            u=pre[u];
        }
        return ans;
    }
    int n,f,d;
    int main()
    {
       while(scanf("%d%d%d",&n,&f,&d)!=EOF)
       {
           memset(head,-1,sizeof(head));ecnt=0;
           scr=0;sink=f+d+n+1;vn=sink+1;
           for(int i=1;i<=f;i++)//食物
           {
               int v;
               scanf("%d",&v);
               Insert(scr,i,v);
           }
           for(int i=1+f;i<=d+f;i++) //饮料
           {
               int v;
               scanf("%d",&v);
               Insert(i,sink,v);       }
           char t[220];
           for(int i=1;i<=n;i++)        //食物
           {
                scanf("%s",t);
                for(int j=0;j<strlen(t);j++)
                {
                    if(t[j]=='Y')
                    Insert(j+1,i+f+d,1);
                }
           }
           for(int i=1;i<=n;i++)        //饮料
           {
               scanf("%s",t);
                for(int j=0;j<strlen(t);j++)
                {
                    if(t[j]=='Y')
                    Insert(i+f+d,j+1+f,1);
                }
           }
        printf("%d\n",Sap(scr,sink,vn));
       }
       return 0;
    }
    


     

  • 相关阅读:
    剑指offer:复杂链表的复制
    剑值offer:最小的k个数
    剑指offer:第一个只出现一次的字符
    剑指offer:树的子结构
    leetcode 240搜索二维矩阵
    leetcode 22括号生成
    leetcode 79 单词搜索
    leetcode 17电话号码的字母组合
    leetcode 78子集
    leetcode 105从前序与中序遍历序列构造二叉树
  • 原文地址:https://www.cnblogs.com/amourjun/p/5134144.html
Copyright © 2011-2022 走看看