HDU3605Escape(最大流SAP+状态压缩优化点的个数)

Escape

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)

Total Submission(s): 6239    Accepted Submission(s): 1474

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

2010 ACM-ICPC Multi-University Training
Contest(17)——Host by ZSTU

题意:现在地球有n(<=100w)人数要去m(<=10)个其他星球生存,接下来n行每行m列,如果第i 为 1 对应这个人可去星球 i ,第 i 个星球最多可容ai个人(最后一行给出m个数)。现在问是否所有的人都可以到其他星球生存。

解题:最大流SAP。建图:因为人数多,而去星球的状态少最多是1024种,所以可以把每种状态看作是点,源点与每种状态连接一条边,容量为当前状态的人数,再每种状态与相应的星球连边,边容为当前状态的人数。再每个星球与汇点连边,边容为星球能容纳的人数。

另一种方法解:多重匹配,人作x部分和星球作y部分,形成二部图。

下面是最大流SAP解法:用G++  。

#include<stdio.h>
#include<string.h>
#include<queue>
#include<algorithm>
using namespace std;
#define captype int

const int MAXN = 1030;   //点的总数
const int MAXM = 14000;    //边的总数
const int INF = 1<<30;

struct EDG{
    int to,next;
    captype cap,flow;
} edg[MAXM];
int eid,head[MAXN];
int gap[MAXN];  //每种距离(或可认为是高度)点的个数
int dis[MAXN];  //每个点到终点eNode 的最短距离
int cur[MAXN];  //cur[u] 表示从u点出发可流经 cur[u] 号边
int pre[MAXN];

inline void init(){
    eid=0;
    memset(head,-1,sizeof(head));
}
//有向边 三个参数,无向边4个参数
inline void addEdg(int u,int v,captype c,captype rc=0){
    edg[eid].to=v; edg[eid].next=head[u];
    edg[eid].cap=c; edg[eid].flow=0; head[u]=eid++;

    edg[eid].to=u; edg[eid].next=head[v];
    edg[eid].cap=rc; edg[eid].flow=0; head[v]=eid++;
}
inline captype maxFlow_sap(int& sNode,int& eNode, int n){//n是包括源点和汇点的总点个数,这个一定要注意
    memset(gap,0,sizeof(gap));
    memset(dis,0,sizeof(dis));
    memcpy(cur,head,sizeof(head));
    pre[sNode] = -1;
    gap[0]=n;
    captype ans=0;  //最大流
    int u=sNode  , i ;
    while(dis[sNode]<n){   //判断从sNode点有没有流向下一个相邻的点
        if(u==eNode){   //找到一条可增流的路
            captype Min=INF ;
            int inser ;
            i=pre[u] ;
            while( i!=-1 ){    //从这条可增流的路找到最多可增的流量Min
                if(Min>edg[i].cap-edg[i].flow){
                    Min=edg[i].cap-edg[i].flow;
                    inser=i;
                }
                i=pre[edg[i^1].to];
            }

            i=pre[u];
            while( i!=-1 ){
                edg[i].flow+=Min;
                edg[i^1].flow-=Min;  //可回流的边的流量
                i=pre[edg[i^1].to];
            }
            ans+=Min;
            u=edg[inser^1].to;
            continue;
        }
        bool flag = false;  //判断能否从u点出发可往相邻点流
        int v;
        i=cur[u];
        while(  i!=-1 ){
            v=edg[i].to;
            if(edg[i].cap-edg[i].flow>0 && dis[u]==dis[v]+1){
                flag=true;
                cur[u]=pre[v]=i;
                break;
            }
            i=edg[i].next;
        }
        if(flag){
            u=v;
            continue;
        }
        //如果上面没有找到一个可流的相邻点,则改变出发点u的距离(也可认为是高度)为相邻可流点的最小距离+1
        int Mind= n;
        i=head[u];
        while(  i!=-1 ){
             if(edg[i].cap-edg[i].flow>0 && Mind>dis[edg[i].to]){
                 Mind=dis[edg[i].to];
                 cur[u]=i;
             }
            i=edg[i].next;
        }

        gap[dis[u]]--;
        if(gap[dis[u]]==0) return ans;  //当dis[u]这种距离的点没有了,也就不可能从源点出发找到一条增广流路径
                                        //因为汇点到当前点的距离只有一种,那么从源点到汇点必然经过当前点,然而当前点又没能找到可流向的点,那么必然断流
        dis[u]=Mind+1;//如果找到一个可流的相邻点,则距离为相邻点距离+1,如果找不到,则为n+1
        gap[dis[u]]++;
        if(u!=sNode) u=edg[pre[u]^1].to;  //退一条边
    }
    return ans;
}
inline void scanf(int& valu){
    char ch;
    while(ch=getchar()){
        if(ch>='0'&&ch<='9')
            break;
    }
    valu=ch-'0';
    while(ch=getchar()){
        if(ch<'0' || ch>'9')
            break;
        valu=valu*10+ch-'0';
    }
}

int main(){
    int n,m,a , s ,t ,ans ,k[1030] ;
    while(scanf("%d%d",&n,&m)>0){
        memset(k,0,sizeof(k));
        int id=0 , i=0 ,j;
        while(i<n){
            int b=0;
            j=0;
            while( j<m ){
                scanf(a);   if(a) b|=1<<j; j++;
            }
            if(k[b]==0&&b) //出现状态的不同个数e
                id++;
            k[b]++;
            i++;
        }
        ans=n;
        init();

        n=id;
        s=0; t= n+m+1;
        i=(1<<m)-1;
        while(i>0 ){
            if(k[i]>0){ //出现的状态
                addEdg(s , id , k[i]);
                j=0;
                while( (1<<j)<=i ){
                    if(i&(1<<j)) addEdg( id , j+n+1 , k[i]); j++;
                }
                id--;
            }
            i--;
        }
        j=0;
        while( j<m ){
            scanf(a);   if(a) addEdg(j+n+1 , t , a);  j++;
        }
        ans-=maxFlow_sap(s , t, t+1);
        if(ans)
            puts("NO");
        else
            puts("YES");
       // printf("%s\n",ans>0?:);
    }
}
时间: 2024-12-22 09:37:39

HDU3605Escape(最大流SAP+状态压缩优化点的个数)的相关文章

HDU 4309 Seikimatsu Occult Tonneru(最大流SAP+状态压缩枚举)

Seikimatsu Occult Tonneru Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2012    Accepted Submission(s): 523 Problem Description During the world war, to avoid the upcoming Carpet-bombing fro

UVA 11008--Antimatter Ray Clearcutting+状态压缩记忆化搜索

题目链接:点击进入 最多只有16个点,如果不用状态压缩的话,最优子结构没法找到.所以我们进行状态压缩,用一个数表示当前的状态,对应二进制位为1表示该位置的树还未被砍掉,为0表示已被砍掉,初始状态为(1< #include<iostream> #include<cstdio> #include<cstring> using namespace std; #define maxn 20 #define INF 0x3f3f3f3f typedef struct { i

hdu3605(最大流+状态压缩)

传送门:Escape 题意:给出每个人适合住的星球信息和该星球能住多少人 ,第一行给出n m 代表有 n 个人 m 个星球,然后接下来n行每行m个数字 1代表适合第 i 个星球 0 代表不适合第 i 个星球,最后一行m个数表示第 i 个星球最多可以住多少个人,问是不是所有人都可以住到星球上. 分析:很裸的最大流,但刚开始直接去建图,100W级别的边MLE了,就算没MLE也会TLE的,因此需要状态压缩,m<=10,最多1024种状态,边数降成1W级别,最大流妥妥的A了. #pragma comme

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

uva 11195 Another queen (用状态压缩解决N后问题)

题目链接:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2136 Problem A Another n-Queen Problem I guess the n-queen problem is known by every person who has studied backtracking. In this problem you s

dp状态压缩

dp状态压缩 动态规划本来就很抽象,状态的设定和状态的转移都不好把握,而状态压缩的动态规划解决的就是那种状态很多,不容易用一般的方法表示的动态规划问题,这个就更加的难于把握了.难点在于以下几个方面:状态怎么压缩?压缩后怎么表示?怎么转移?是否具有最优子结构?是否满足后效性?涉及到一些位运算的操作,虽然比较抽象,但本质还是动态规划.找准动态规划几个方面的问题,深刻理解动态规划的原理,开动脑筋思考问题.这才是掌握动态规划的关键. 动态规划最关键的要处理的问题就是位运算的操作,容易出错,状态的设计也直

poj 3254 Corn Fields(状态压缩dp)

Description Farmer John has purchased a lush new rectangular pasture composed of M by N (1 ≤ M ≤ 12; 1 ≤ N ≤ 12) square parcels. He wants to grow some yummy corn for the cows on a number of squares. Regrettably, some of the squares are infertile and

hoj 2662 状态压缩dp

题意: 给定mxn的棋盘,要往其中放d枚棋子,其中,一枚棋子的上下左右四个位置不能再放棋子.求所有合法的放置状态 ( 0<m,n<=80 , mxn<=80 ) 棋盘位置可多达80,爆搜目测超时,我用的状态压缩dp. 棋盘中的一个格子,放棋用1,不放用0 压缩其中一维,每个状态数用一个二进制数表示. 每个状态都是棋盘一行的放置方法 假设,m >= n , 这个递推棋盘就有 m行 ,每行至多有 2^n-1个状态数.其实,没有这么多!按照题意,每个1的上下左右不能有1.对于一行,只知左

ACM/ICPC 之 BFS+状态压缩(POJ1324(ZOJ1361))

求一条蛇到(1,1)的最短路长,题目不简单,状态较多,需要考虑状态压缩,ZOJ的数据似乎比POj弱一些 POJ1324(ZOJ1361)-Holedox Moving 题意:一条已知初始状态的蛇,求其到(1,1)的最短路长 题解:开始做的时候用BFS暴力做了一次,结果RE了,后来看了其他的题解和discuss才转向状态压缩.也看到有人用A*做出来了. 现在简要介绍一下状态压缩的思路: 由于蛇身最长只有8,可以利用两条相邻蛇身坐标确定其相对方向(四个方向),两位二进制可以表示 这样 一个蛇头坐标+