hdu3605(最大流+状态压缩)

传送门:Escape

题意:给出每个人适合住的星球信息和该星球能住多少人 ,第一行给出n m 代表有 n 个人 m 个星球,然后接下来n行每行m个数字 1代表适合第 i 个星球 0 代表不适合第 i 个星球,最后一行m个数表示第 i 个星球最多可以住多少个人,问是不是所有人都可以住到星球上。

分析:很裸的最大流,但刚开始直接去建图,100W级别的边MLE了,就算没MLE也会TLE的,因此需要状态压缩,m<=10,最多1024种状态,边数降成1W级别,最大流妥妥的A了。

#pragma comment(linker,"/STACK:1024000000,1024000000")
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <limits.h>
#include <iostream>
#include <algorithm>
#include <queue>
#include <cstdlib>
#include <stack>
#include <vector>
#include <set>
#include <map>
#define LL long long
#define mod 100000000
#define inf 0x3f3f3f3f
#define eps 1e-6
#define N 10010
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define PII pair<int,int>
using namespace std;
inline int read()
{
    char ch=getchar();int x=0,f=1;
    while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-1;ch=getchar();}
    while(ch<=‘9‘&&ch>=‘0‘){x=x*10+ch-‘0‘;ch=getchar();}
    return x*f;
}
int n,m,sum,vs,vt,tot,NV;
int pre[N],cur[N],h[N],q[N];
struct edge
{
    int u,v,w,next;
    edge() {}
    edge(int u,int v,int w,int next):u(u),v(v),w(w),next(next) {}
} e[N*20];
void addedge(int u,int v,int w)
{
    e[tot]=edge(u,v,w,pre[u]);
    pre[u]=tot++;
    e[tot]=edge(v,u,0,pre[v]);
    pre[v]=tot++;
}
void init()
{
    memset(pre,-1,sizeof(pre));
    tot=0;
}

/*******************dinic************************/
int bfs()
{
    int head=0,tail=1;
    memset(h,-1,sizeof(h));
    q[0]=vs;h[vs]=0;
    while(head!=tail)
    {
        int u=q[head++];
        for(int i=pre[u];~i;i=e[i].next)
        {
            int v=e[i].v,w=e[i].w;
            if(w&&h[v]==-1)
            {
                h[v]=h[u]+1;
                q[tail++]=v;
            }
        }
    }
    return h[vt]!=-1;
}

int dfs(int u,int flow)
{
    if(u==vt)return flow;
    int used=0;
    for(int i=cur[u];~i;i=e[i].next)
    {
        int v=e[i].v,w=e[i].w;
        if(h[v]==h[u]+1)
        {
            w=dfs(v,min(flow-used,w));
            e[i].w-=w;e[i^1].w+=w;
            if(e[i].w)cur[u]=i;
            used+=w;
            if(used==flow)return flow;
        }
    }
    if(!used)h[u]=-1;
    return used;
}
int dinic()
{
    int res=0;
    while(bfs())
    {
        for(int i=vs;i<=vt;i++)cur[i]=pre[i];
        res+=dfs(vs,inf);
    }
    return res;
}
/********************dinic***********************/
int x,state,a[N];
void build()
{
    vs=0;vt=(1<<m)+m+1;
    memset(a,0,sizeof(a));
    for(int i=1;i<=n;i++)
    {
        state=0;
        for(int j=0;j<m;j++)
        {
            x=read();
            if(x)state|=(1<<j);
        }
        a[state]++;
    }
    for(int i=0;i<(1<<m);i++)
    {
        if(a[i])
        {
            addedge(vs,i+1,a[i]);
            for(int j=0;j<m;j++)
            {
                if(i&(1<<j))
                    addedge(i+1,j+1+(1<<m),a[i]);
            }
        }
    }
    for(int i=0;i<m;i++)
    {
        x=read();
        addedge((1<<m)+i+1,vt,x);
    }
    if(dinic()==n)puts("YES");
    else puts("NO");
}
int main()
{
    while(scanf("%d%d",&n,&m)>0)
    {
        init();
        build();
    }
}

时间: 2024-10-09 17:01:48

hdu3605(最大流+状态压缩)的相关文章

HDU 3605 最大流+状态压缩

Escape Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 9920    Accepted Submission(s): 2372 Problem Description 2012 If this is the end of the world how to do? I do not know how. But now scienti

Escape(状态压缩+最大流,好题)

Escape http://acm.hdu.edu.cn/showproblem.php?pid=3605 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 13201    Accepted Submission(s): 3329 Problem Description 2012 If this is the end of the wor

软件补丁问题(状态压缩 最短路)

先状态压缩,再求费用流,但耗内存太大,改变存边方式降低内存使用. 直接求最短路即可 //http://www.cnblogs.com/IMGavin/ #include <iostream> #include <stdio.h> #include <cstdlib> #include <cstring> #include <queue> #include <vector> #include <map> #include &

状态压缩DP与TSP问题

状态压缩DP DP过程中的状态不可能像背包问题一样只有整数,肯定有各种各样稀奇古怪的状态,需要不止一个变量来表示.这种情况下如果需要使用DP 就必须把状态压缩成一个数来表示,并且一个数只能对应于一种状态. 特别地,对于集合我们可以把每一个元素的选取与否对应到一个二进制位里,从而把状态压缩成一个整数,大大方便了计算和维护. 对于不是整数的情况,很多时候很难确定一个合适的递推顺序,因此使用记忆化搜索可以避免这个问题.如下面TSP问题的法一. TSP问题 一张图上有n个点,给定相应的邻接矩阵,需要求出

FZU1892接水管游戏-BFS加上简单的状态压缩和位运算处理

原题地址:http://acm.fzu.edu.cn/problem.php?pid=1892 Problem 1892 接水管游戏 Accept: 108    Submit: 498 Time Limit: 1000 mSec    Memory Limit : 32768 KB Problem Description 接水管游戏的规则如下: 1.在N*N大小的方格上有两个特别的水管,分别为进水口和出水口: 2.有7种1*1大小的水管需要放在这N*N大小的方格内,使得水流能够从进水口经过这些

hdu3605最大流

题意:给n个人m个星球,每个人适不适合去某个星球,每个星球的最大容量,看能不能满足所有人能去一个星球 题解:可以看出如果直接建边,边的个数是1e5左右的,这样时间肯定会爆掉,那么我们考虑用二进制状态压缩,对于能去相同的星球的全部压缩成一个点,和星球连边,权值为能去的个数,然后这样就只有(1<<10)个左右,(其实是队友想出来的做法= =),星球连向汇点,权值为星球容量,然后跑最大流就好了 #include<bits/stdc++.h> #define fi first #defin

胜利大逃亡(续)(状态压缩bfs)

胜利大逃亡(续) Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 7357    Accepted Submission(s): 2552 Problem Description Ignatius再次被魔王抓走了(搞不懂他咋这么讨魔王喜欢)……这次魔王汲取了上次的教训,把Ignatius关在一个n*m的地牢里,并在地牢的某些地方安装了带

uva 818(dfs+图+状态压缩)

题意:有n个环,编号从1到n,给出了一些环环相扣的情况,比如给a和b表示a和b两个环的扣在一起的,每个环都是可以打开的,问最少打开多少个环,然后再扣好,可以让所有的环成为一条链. 题解:状态压缩把所有的打开环的情况枚举出来,然后拿去判断是否成立,更新打开环后的图g[i][j],和每个点的度数,不成立有三种情况,1.计算没有打开的环的度数,如果大于2说明不会有链,2.把没有打开环拿去dfs,访问过就vis[i]++,如果vis[i]>=2说明存在环,3.如果打开的环数num + 1小于链的数量,说

POJ 3254 Corn Fields 状态压缩DP (C++/Java)

http://poj.org/problem?id=3254 题目大意: 一个农民有n行m列的地方,每个格子用1代表可以种草地,而0不可以.放牛只能在有草地的,但是相邻的草地不能同时放牛, 问总共有多少种方法. 思路: 状态压缩的DP. 可以用二进制数字来表示放牧情况并判断该状态是否满足条件. 这题的限制条件有两个: 1.草地限制. 2.相邻限制. 对于草地限制,因为输入的时候1是可以种草地的. 以"11110"草地分析,就只有最后一个是不可以种草的.取反后得00001  .(为啥取反