zoukankan      html  css  js  c++  java
  • [Luogu P2891/POJ 3281/USACO07OPEN ]吃饭Dining

    传送门:https://www.luogu.org/problemnew/show/P2891

    题面

    Solution

    网络流

    先引用一句真理:网络流最重要的就是建模

    今天这道题让我深有体会

    首先,观察数据范围,n=100,一般这种100-1000的图论题,很有可能是网络流.

    那就直接从网络流的角度入手

    考虑这样建模

    建模要点如下:

    1.建权值为1的边,保证每个食物和水仅用一次

     2.没了

    对以上的图求一个最大流,那不就是我们想要的最大的匹配数吗?

    看起来是不是很OjbK?

    其实不然,这样子一头牛有可能脚踏N条食物和水,但是题目要求一头牛只能吃喝一次

    反例如下:

    所以说,我们要对一头牛吃的东西做一个限制,保证其只流过1

    怎么限制呢?

    直接把一头牛拆成两头牛,中间连一条边就OK了嘛

    如下图:

    接下来就可以考虑如何给点编号了

    我的编号方法很直接,很暴力

    源点:1

    食物: 2 ~  2+f-1

    牛   2+f ~ 2+f+2n -1 

    水: 2+f+2n ~ 2+f+2n+d

    汇点:1000

    如下图所示

    按照以上方法,每种物品对应的点为:

    食物i : 1+i

    牛i : 1+f+i

    牛i的右边的分点:  1+f+n+i

    水i: 1+f+2*n+i

    然后dinic直接求一波最大流就可以带走啦

    DINIC教程传送门: http://www.cnblogs.com/SYCstudio/p/7260613.html (个人感觉写得很清楚)

    Code

    //Luogu P2891 [USACO07OPEN]吃饭Dining
    //Apr,2ed,2018
    //Dinic求最大流
    #include<iostream>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    using namespace std;
    long long read()
    {
        long long x=0,f=1; char c=getchar();
        while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
        while(isdigit(c)){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    const int N=100+10;
    const int M=N*10;
    const int inf=0x3f3f3f3f;
    struct line
    {
        int t,rev,w;
    };
    vector <line> e[M];
    inline void AddLine(int s,int t)
    {
        line temp;
        temp.t=t,temp.rev=e[t].size(),temp.w=1;
        e[s].push_back(temp);
        temp.t=s,temp.rev=e[s].size()-1,temp.w=0;
        e[t].push_back(temp);
    }
    int n,f,d;
    int dl[M],head,tail,depth[M];
    bool visited[M];
    bool bfs()
    {
        memset(visited,0,sizeof visited);
        dl[1]=1,depth[1]=1;
        visited[1]=true;
        head=1,tail=2;
        while(head<tail)
        {
            int now=dl[head],size=e[now].size();
            for(int i=0;i<size;i++)
                if(visited[e[now][i].t]==false and e[now][i].w>0)
                {
                    visited[e[now][i].t]=true;
                    dl[tail++]=e[now][i].t;
                    depth[e[now][i].t]=depth[now]+1;
                }
            head++;
        }
        return visited[1000];
    }
    int dfs(int now,int f)
    {
        if(now==1000)
            return f;
        int size=e[now].size(),ans=0;
        for(int i=0;i<size;i++)
            if(depth[e[now][i].t]==depth[now]+1 and e[now][i].w>0)
            {
                int t_ans=dfs(e[now][i].t,min(f,e[now][i].w));
                e[now][i].w-=t_ans;
                e[e[now][i].t][e[now][i].rev].w+=t_ans;
                f-=t_ans,ans+=t_ans;
                if(f==0) break;
            }
        return ans;
    }
    int Dinic()
    {
        int ans=0;
        while(bfs())
            ans+=dfs(1,inf);
        return ans;
    }
    int main()
    {
        n=read(),f=read(),d=read();
        for(int i=1;i<=1000;i++)
            e[i].reserve(16);
        for(int i=1;i<=f;i++)
            AddLine(1,1+i);
        for(int i=1;i<=d;i++)
            AddLine(1+f+2*n+i,1000);
        for(int i=1;i<=n;i++)
        {
            int F=read(),D=read(),temp;
            for(int j=1;j<=F;j++)
            {
                temp=read();
                AddLine(1+temp,1+f+i);
            }
            for(int j=1;j<=D;j++)
            {
                temp=read();
                AddLine(1+f+n+i,1+f+2*n+temp);
            }
        }
        for(int i=1;i<=n;i++)
            AddLine(1+f+i,1+f+n+i);
            
        printf("%d",Dinic());
        return 0;
    }
    C++

    后记

    写的时候发现自己真的有点生疏了,这种比较靠记忆的算法还是久不久搞一下来恢复记忆为妙

    网络流的时间复杂度真玄学

    自己选择的路,跪着也要走完。朋友们,虽然这个世界日益浮躁起来,只要能够为了当时纯粹的梦想和感动坚持努力下去,不管其它人怎么样,我们也能够保持自己的本色走下去。
  • 相关阅读:
    移动web开发之flex布局(弹性布局)
    移动web开发之流式布局
    移动端基础
    3D变形(CSS3) transform
    动画(CSS3) animation
    2D变形(CSS3) transform
    过渡(CSS3)
    CSS精灵技术(sprite)
    字体图标
    伸缩布局(CSS3)
  • 原文地址:https://www.cnblogs.com/GoldenPotato/p/8697971.html
Copyright © 2011-2022 走看看