zoukankan      html  css  js  c++  java
  • HDU 3605Escape(缩点+网络流之最大流)

    题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=3605

    本来打算昨天写两道题的,结果这个题卡住了,最后才发现是最后的推断条件出错了,推断满流的条件应该是与n的比較,居然写成与全部星球总容量的比較了。(近期大脑短路。。)

    这题也不是全然自己想的,没想到缩点这一技巧,由于n的数据范围太大,普通的建图方法会超时超内存,须要缩点,由于对于每一个点来说,一共仅仅有2^10种方法,而最多一共同拥有10W个点,显然有非常多点是反复的,这时能够採取缩点的方法,将反复的当成一个点来处理。这样数据范围就缩小到了1024个点,速度大大提升。

    建图思路是建一源点与汇点,将每种方法与源点相连,权值为这样的方法反复的次数,将每一个星球与汇点相连,权值为每一个星球的最大容量,再将每种方法与星球相连,权值为INF,最后推断是否满流。

    代码例如以下:

    #include <iostream>
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <math.h>
    #include <ctype.h>
    #include <queue>
    #include <map>
    #include <algorithm>
    
    using namespace std;
    const int INF=1e9;
    int head[2000], s, t, nv, n, cnt;
    int num[2000], d[2000], pre[2000], cur[2000], q[2000], fei[2000];
    struct node
    {
        int u, v, next, cap;
    }edge[1000000];
    void add(int u, int v, int cap)
    {
        edge[cnt].v=v;
        edge[cnt].cap=cap;
        edge[cnt].next=head[u];
        head[u]=cnt++;
    
        edge[cnt].v=u;
        edge[cnt].cap=0;
        edge[cnt].next=head[v];
        head[v]=cnt++;
    }
    void bfs()
    {
        memset(num,0,sizeof(num));
        memset(d,-1,sizeof(d));
        int f1=0, f2=0, i;
        q[f1++]=t;
        d[t]=0;
        num[0]=1;
        while(f1>=f2)
        {
            int u=q[f2++];
            for(i=head[u];i!=-1;i=edge[i].next)
            {
                int v=edge[i].v;
                if(d[v]==-1)
                {
                    d[v]=d[u]+1;
                    num[d[v]]++;
                    q[f1++]=v;
                }
            }
        }
    }
    int isap()
    {
        memcpy(cur,head,sizeof(cur));
        int flow=0, i, u=pre[s]=s;
        bfs();
        while(d[s]<nv)
        {
            if(u==t)
            {
                int f=INF, pos;
                for(i=s;i!=t;i=edge[cur[i]].v)
                {
                    if(f>edge[cur[i]].cap)
                    {
                        f=edge[cur[i]].cap;
                        pos=i;
                    }
                }
                for(i=s;i!=t;i=edge[cur[i]].v)
                {
                    edge[cur[i]].cap-=f;
                    edge[cur[i]^1].cap+=f;
                }
                flow+=f;
                if(flow>=n)
                    return flow;
                u=pos;
            }
            for(i=cur[u];i!=-1;i=edge[i].next)
            {
                if(d[edge[i].v]+1==d[u]&&edge[i].cap)
                {
                    break;
                }
            }
            if(i!=-1)
            {
                cur[u]=i;
                pre[edge[i].v]=u;
                u=edge[i].v;
            }
            else
            {
                if(--num[d[u]]==0) break;
                int mind=nv;
                for(i=head[u];i!=-1;i=edge[i].next)
                {
                    if(mind>d[edge[i].v]&&edge[i].cap)
                    {
                        mind=d[edge[i].v];
                        cur[u]=i;
                    }
                }
                d[u]=mind+1;
                num[d[u]]++;
                u=pre[u];
            }
        }
        return flow;
    }
    int main()
    {
        int m, x, i, j, top, y, z, num, a[20];
        while(scanf("%d%d",&n,&m)!=EOF)
        {
            memset(head,-1,sizeof(head));
            memset(fei,0,sizeof(fei));
            cnt=0;
            s=0;
            top=0;
            num=0;
            for(i=1;i<=n;i++)
            {
                x=0;
                for(j=1;j<=m;j++)
                {
                    scanf("%d",&y);
                    x=x*2+y;
                }
                fei[x]++;
            }
            for(i=1;i<=1100;i++)
            {
                if(fei[i])
                {
                    num++;
                }
            }
            t=num+m+1;
            nv=t+1;
            for(i=1;i<=1100;i++)
            {
                if(fei[i])
                {
                    //printf("--%d %d
    ", i, fei[i]);
                    top++;
                    add(s,top,fei[i]);
                    x=i;
                    z=m+1;
                    while(x)
                    {
                        y=x%2;
                        z--;
                        if(y)
                        {
                            add(top,z+num,INF);
                        }
                        //printf("--%d %d %d %d--",y, top, z, num);
                        x=x/2;
                    }
                    //printf("
    ");
                }
            }
            for(i=1;i<=m;i++)
            {
                scanf("%d",&x);
                add(i+num,t,x);
            }
            x=isap();
            if(x>=n)
                printf("YES
    ");
            else
                printf("NO
    ");
        }
        return 0;
    }
    


  • 相关阅读:
    python的冒泡法和二分法的总结
    python生成器应用中的一个要点
    Dart 入门初体验
    使用 mui jquery javascript 实现智能提示功能
    mui 输入框调整字体的样式
    人人商城怎样自定义的会员中心页,让不同用户组看到不同的列表导航
    人人商城 微信支付提示 当前页面的URL未注册
    通过 PDO 实现简单的 CRUD
    PHPStorm 通过 Material Theme UI 设置新主题
    CodeIgniter 3.x 学习笔记
  • 原文地址:https://www.cnblogs.com/gcczhongduan/p/4296425.html
Copyright © 2011-2022 走看看