hdu 3605 最大流



 


http://hi.baidu.com/yy17yy/item/a7896b345eaa81f3e6bb7a59





3604WA了,,实在调不动了,,,,

 

这个题,,直接建图会TLE,,,,

 

压缩:

把人的可选集合看作一个状态,,,那么,,,最多会有1024个状态,,,而人总数有10万个,,就是说有大量重复,,,于是把这些重复的压缩掉,,,

 

数据量真的很大,,,memset全部也会TLE,,

 

#include <iostream>
#include <stdio.h>
#include <memory.h>
using namespace std;
const int N=2010;
struct edg
{
    int to,nxt,w;
}e[N*20];

int h[N],gap[N],p[N],n;
void add(int x,int y,int w,int &j)
{
    e[j].to=y;e[j].w=w;e[j].nxt=p[x];p[x]=j++;
    e[j].to=x;e[j].w=0;e[j].nxt=p[y];p[y]=j++;
}
int sap(int u,int flow)
{
    if(u==n)
        return flow;
    int tmp=n-1,low=flow;
    for(int x=p[u];x!=-1;x=e[x].nxt)
    {
        int v=e[x].to;
        if(h[u]==h[v]+1&&e[x].w)
        {
            int f=sap(v,min(e[x].w,low));
            low-=f;e[x].w-=f;e[x^1].w+=f;
            if(low==0||h[n-1]==n)
                return flow-low;
        }
        if(e[x].w)
            tmp=min(tmp,h[v]);
    }
    if(flow==low)
    {
        if(--gap[h[u]]==0)
            h[n-1]=n;
        else
            gap[h[u]=tmp+1]++;
    }
    return flow-low;
}

int dp[N];
int sum[22];
int main()
{
    int nn,mm;
    while(~scanf("%d%d",&nn,&mm))
    {
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=nn;i++)
        {
            int s=0;
            for(int j=0;j<mm;j++)
            {
                int x;
                scanf("%d",&x);
                s|=x<<j;
            }
            dp[s]++;
        }

        for(int i=0;i<mm;i++)
            scanf("%d",&sum[i]);

        int tot=1<<mm;
        int num=0;
        for(int s=0;s<tot;s++)
            if(dp[s])
                num++;
        n=num+mm+2;

        int id=1;
        int j=0;
        fill(p,p+n+1,-1);
        for(int s=0;s<tot;s++)
            if(dp[s])
            {
                add(n-1,id,dp[s],j);
                for(int k=0;k<mm;k++)
                {
                    int tk=1<<k;
                    if(tk&s)
                        add(id,num+k+1,dp[s],j);
                }
                id++;
            }
        for(int i=0;i<mm;i++)
            add(num+i+1,n,sum[i],j);
        fill(h,h+n+1,0);
        fill(gap,gap+n+1,0);
        gap[0]=n;
        int ans=0;
        while(h[n-1]<n)
            ans+=sap(n-1,1<<29);
        puts(ans==nn?"YES":"NO");
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值