• POJ 3281 Dining


    这个题写了一天,现在才过......

    一开始想到了二分图的最大匹配,每种组合连边,算出最多的。结果仔细一想是错的,因为没有考虑到一个牛只能选一组。

    然后就想到开始建图跑最大流了,一开始采用了 源点-->牛-->食物in-->食物out-->饮料-->汇点  这样的模式建图。结果一直WA,看了Discuss,发现是错的。

    拆食物错的原因在于:
    如果拆食物,按照牛->食物-in->食物-out->饮料 这样建图的话,虽然保证了流量的限制,每头牛也只能选一种食物和饮料。
    但是食物-out->饮料之间的边就失去的牛的编号性,就成了没有针对哪头牛的组合,不知道某些边是哪些牛的喜好。
    这样就会导致某头牛明明不喜欢某种搭配,但是因为有其他牛喜欢这种搭配,使得这头牛“强行”被选择了这种搭配。自然就WA了。

    然后就只能用  源点-->食物-->牛in-->牛out-->饮料--汇点 这样的模式建图。

    恶心的是,刘汝佳白书的Dinic居然TLE了... ...然后找了个非递归的Dinic AC了。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    using namespace std;
    const int maxn=1000;
    const int inf=1<<20;
    //******************************************//
    struct Node
    {
        int v,next;
        int val;
    }edge[maxn*maxn*2];
    
    int level[maxn];//顶点的层次
    int head[maxn];
    int que[maxn*10];//BFS中用于遍历的顶点,DFS求增广中记录边
    int out[10*maxn];//DFS用于几乎定点的分支
    int ind;
    
    void init()
    {
        ind=0;
        memset(head,-1,sizeof(head));
    }
    void addedge(int x,int y,int z)
    {
        edge[ind].v=y;
        edge[ind].val=z;
        edge[ind].next=head[x];
        head[x]=ind++;
        edge[ind].v=x;
        edge[ind].val=0;
        edge[ind].next=head[y];
        head[y]=ind++;
    }
    int dinic(int n,int source,int sink)
    {
        int ret=0;
        int h=0,r=0;
        while(1)//DFS
        {
            int i;
            for(i=0;i<=n;++i)
                level[i]=0;
            h=0,r=0;
            level[source]=1;
            que[0]=source;
            while(h<=r)//BFS
            {
                int  t=que[h++];
                for(i=head[t];i!=-1;i=edge[i].next)
                    {
                        if(edge[i].val&&level[edge[i].v]==0)
                            {
                              level[edge[i].v]=level[t]+1;
                              que[++r]=edge[i].v;
                            }
                    }
            }
    
            if(level[sink]==0)break;//找不到汇点
            for(i=0;i<=n;++i)
              out[i]=head[i];
    
            int  q=-1;
            while(1)
            {
                if(q<0)
                {
                    int cur=out[source];
                    for(;cur!=-1;cur=edge[cur].next)
                    {
                        if(edge[cur].val&&out[edge[cur].v]!=-1&&level[edge[cur].v]==2)
                        {
                            break;
                        }
                    }
                    if(cur>=0)
                    {
                        que[++q]=cur;
                        out[source]=edge[cur].next;
                    }
                    else
                        break;
                }
                int  u=edge[que[q]].v;
                if(u==sink)//一条增广路
                {
                    int  dd=inf;
                    int  index=-1;
                    for(i=0;i<=q;i++)
                    {
                        if(dd>edge[que[i]].val)
                        {
                            dd=edge[que[i]].val;
                            index=i;
                        }
                    }
                    ret+=dd;
                    for(i=0;i<=q;i++)
                    {
                        edge[que[i]].val-=dd;
                        edge[que[i]^1].val+=dd;
                    }
                    for(i=0;i<=q;i++)
                    {
                        if(edge[que[i]].val==0)
                        {
                            q=index-1;
                            break;
                        }
                    }
                }
                else
                {
                    int cur=out[u];
                    for(;cur!=-1;cur=edge[cur].next)
                    {
                        if(edge[cur].val&&out[edge[cur].v]!=-1&&level[u]+1==level[edge[cur].v])
                        {
                            break;
                        }
                    }
                    if(cur!=-1)
                    {
                        que[++q]=cur;
                        out[u]=edge[cur].next;
                    }
                    else
                    {
                        out[u]=-1;
                        q--;
                    }
                }
            }
        }
        return ret;
    }
    int N,F,D,ff,dd;
    int FF[maxn],DD[maxn];
    
    //输入输出
    int main()
    {
        while(~scanf("%d%d%d", &N, &F, &D))
        {
            init();
    
          //  s=0;
         //   t=2*N+F+D+1;
            for(int i=2*N+1;i<=2*N+F;i++)
                addedge(0,i,1);
            for(int i=2*N+1+F;i<=2*N+F+D;i++)
                addedge(i,2*N+F+D+1,1);
            for(int i=1;i<=N;i++)
                addedge(i,i+N,1);
            for(int i=1;i<=N;i++)
            {
                scanf("%d%d",&ff,&dd);
                for(int j=1;j<=ff;j++) scanf("%d",&FF[j]);
                for(int j=1;j<=dd;j++) scanf("%d",&DD[j]);
                for(int j=1;j<=ff;j++)
                    for(int k=1;k<=dd;k++)
                    {
                        addedge(2*N+FF[j],i,1);
                        addedge(i+N,2*N+F+DD[k],1);
                    }
            }
            printf("%d
    ",dinic(2*N+F+D+10,0,2*N+F+D+1));
        }
        return 0;
    }
  • 相关阅读:
    c++调用win32API控制打印机打印
    php socket 通信
    [SDOI2015][BZOJ3991] 寻宝游戏|set|dfs序|虚树|树上倍增LCA
    [NOI2015][BZOJ4195] 程序自动分析|并查集|离散化
    [NOI2015][BZOJ4196] 软件包管理器|树链剖分
    [HEOI2014][BZOJ3611] 大工程|虚树|树型dp|dfs序|树上倍增LCA
    [Usaco2007 Mar][BZOJ1638] Cow Traffic 奶牛交通|动态规划
    [HDU2222]Keywords Search|AC自动机
    [POI2007][BZOJ1103] 大都市meg|dfs序|树状数组
    [Usaco2007 Dec][BZOJ1690] 奶牛的旅行|分数规划|二分|SPFA
  • 原文地址:https://www.cnblogs.com/zufezzt/p/4734557.html
Copyright © 2020-2023  润新知