HDU 3605 Escape 网络流最大流 合并点

 
 
表面上看这是一道很明显的网络流题目,只要把源点连到所有人上,每个人再连到星球上,星球再连接到汇点即可,但是由于点数太多导致边数也很多,最终超时。 实际上每个人最多就只有10个星球可以选择,也就是1024种可能,那么只要人数超过1024,必定会出现重复的选择情况,而且重复的次数相当多,如果我们把这些选择相同的人合并起来,并且把对应的边的容量也合并起来,就可以将点缩减至1036个,从而降低时间复杂度。
Problem - 3605<script src="/js/global.js" type="text/javascript"></script><script src="/js/register.js" type="text/javascript"></script><script src="/js/MathJax/MathJax/MathJax.js?config=TeX-AMS-MML_HTMLorMML" type="text/javascript"></script>
 

Escape

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 8412    Accepted Submission(s): 1902
Problem Description
2012 If this is the end of the world how to do? I do not know how. But now scientists have found that some stars, who can live, but some people do not fit to live some of the planet. Now scientists want your help, is to determine what all of people can live in these planets.
Input
More set of test data, the beginning of each data is n (1 <= n <= 100000), m (1 <= m <= 10) n indicate there n people on the earth, m representatives m planet, planet and people labels are from 0. Here are n lines, each line represents a suitable living conditions of people, each row has m digits, the ith digits is 1, said that a person is fit to live in the ith-planet, or is 0 for this person is not suitable for living in the ith planet. The last line has m digits, the ith digit ai indicates the ith planet can contain ai people most.. 0 <= ai <= 100000
Output
Determine whether all people can live up to these stars If you can output YES, otherwise output NO.
Sample Input
1 1 1 1 2 2 1 0 1 0 1 1
Sample Output
YES NO
Source
Recommend
lcy

#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;

const int MAXN=400010;
const int MAXM=6000010;
const int INF=99999999;
struct Edge
{
    int to,next,cap,flow;
};


struct Ana
{
    int state[2000][20];
    int flag[2000];
    int time[2000];
    int cnt;
};

Edge edge[MAXM];
int head[MAXN],tol;
int gap[MAXN],dep[MAXN],pre[MAXN],cur[MAXN];
Ana ana;


void init()
{
    tol=0;
    memset(head,-1,sizeof(head));
    memset(ana.flag,-1,sizeof(ana.flag));
    memset(ana.time,0,sizeof(ana.time));
    ana.cnt=0;
}

void addedge(int u,int v,int w,int rw=0)
{
    edge[tol].to=v;
    edge[tol].cap=w;
    edge[tol].next=head[u];
    edge[tol].flow=0;
    head[u]=tol++;
    edge[tol].to=u;
    edge[tol].cap=rw;
    edge[tol].next=head[v];
    edge[tol].flow=0;
    head[v]=tol++;
}

int sap(int start,int end,int N)
{
    memset(gap,0,sizeof(gap));
    memset(dep,0,sizeof(dep));
    memcpy(cur,head,sizeof(head));
    int u=start;
    pre[u]=-1;
    gap[0]=N;
    int ans=0;
    while(dep[start]<N)
    {
        if(u==end)
        {
            int Min=INF;
            for(int i=pre[u];i!=-1;i=pre[edge[i^1].to])
                if(Min>edge[i].cap-edge[i].flow)
                Min=edge[i].cap-edge[i].flow;
            for(int i=pre[u];i!=-1;i=pre[edge[i^1].to])
            {
                edge[i].flow+=Min;
                edge[i^1].flow-=Min;
            }
            u=start;
            ans+=Min;
            continue;
        }
        bool flag=false;
        int v;
        for(int i=cur[u];i!=-1;i=edge[i].next)
        {
            v=edge[i].to;
            if(edge[i].cap-edge[i].flow&&dep[v]+1==dep[u])
            {
                flag=true;
                cur[u]=pre[v]=i;
                break;
            }
        }
        if(flag)
        {
            u=v;
            continue;
        }
        int Min=N;
        for(int i=head[u];i!=-1;i=edge[i].next)
            if(edge[i].cap-edge[i].flow&&dep[edge[i].to]<Min)
        {
            Min=dep[edge[i].to];
            cur[u]=i;
        }
        gap[dep[u]]--;
        if(!gap[dep[u]])
            return ans;
        dep[u]=Min+1;
        gap[dep[u]]++;
        if(u!=start)
            u=edge[pre[u]^1].to;
    }
    return ans;
}





int main()
{
    int n,m;
    int source,sink;
    int tmp;
    int stat[20];
    int ans;
    source=0;
    while(~scanf("%d%d",&n,&m))
    {
        init();

        for(int i=0;i<n;i++)
        {
            ans=0;
            for(int j=0;j<m;j++)
            {
                scanf("%d",&tmp);
                ans=ans*2+tmp;
                stat[j]=tmp;
            }
            if(ana.flag[ans]==-1)
            {
                ana.flag[ans]=ana.cnt;
                ana.time[ana.cnt]++;
                for(int j=0;j<m;j++)
                    ana.state[ana.cnt][j]=stat[j];
                ana.cnt++;
            }
            else
            {
                ana.time[ana.flag[ans]]++;
            }
        }

        sink=ana.cnt+m+1;

        for(int i=0;i<ana.cnt;i++)
        {
            addedge(source,i+1,ana.time[i]);
        }

        for(int i=0;i<ana.cnt;i++)
        {
            for(int j=0;j<m;j++)
            {
                if(ana.state[i][j]!=0)
                {
                    addedge(i+1,ana.cnt+j+1,ana.time[i]);
                }
            }
        }

        for(int i=ana.cnt+1;i<=ana.cnt+m;i++)
        {
            scanf("%d",&tmp);
            addedge(i,sink,tmp);
        }



        ans=(n==sap(source,sink,sink+1));
        if(ans)
            printf("YES\n");
        else
            printf("NO\n");

    }
}
 

查看原文:http://colorfulshark.cn/wordpress/escape-1032.html
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值