【HDU

来源:互联网 发布:千岛片淘宝叫什么 编辑:程序博客网 时间:2024/05/18 02:03

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
题意: n个人,m个星球,每个星球都有自己最大的承受人数,每个人都有自己喜欢的星球(可能有多个),问最后能不能让每个人都有地方住。

其实本题是多重匹配的模板,但是却可以用最大流+状态压缩解,由于菜鸡的我还没有学过状态压缩,就想趁着这次学习一下。

分析一: 最大流+状态压缩
其实匹配问题都是可以用最大流解的,但是这道题,n太大了,就按照最一般的建图,不管什么算法都是过不去的。但是我们可以发现m最大只有10,这么多人选这10个星球,不管怎么选,一定会有许多的重复(注意这里的重复是指,假如有个人仅选择1 3 5 星球,要是有另外一个人也仅选择1 3 5 星球,这时候我们是认为重复)。
每个人我们都可以用10位二进制数来存储其选择的情况,遍历每个人,这样的话,我们就可以得到每种状态下的人数。最后我们遍历所有的状态建边,详细的看代码解释。

#include <cstdio>#include <cstring>#include <queue>#include <algorithm>using namespace std;#define  LL long long#define fread() freopen("in.txt","r",stdin)#define fwrite() freopen("out.txt","w",stdout)const int MAXN = 200000+100  ;const int MAXM = 1000000+100;const int mod = 1e9+7;const int inf = 0x3f3f3f3f;struct Edge {    int form,to,cap,flow,nexts;}edge[MAXM];int head[MAXN],top;void init(){    memset(head,-1,sizeof(head));    top=0;}void addedge(int a,int b,int c){    Edge e={a,b,c,0,head[a]};    edge[top]=e;head[a]=top++;    Edge ee={b,a,0,0,head[b]};    edge[top]=ee;head[b]=top++;}int S,T;int n,m;int cnt[MAXN];void getmap(){    memset(cnt,0,sizeof(cnt));    S=1024+11;T=S+1;  // 最大1<<10中状态 1024     for(int i=1;i<=n;i++){        int temp=0;        for(int j=0;j<m;j++){            int a;scanf("%d",&a);            if(a) temp+=(1<<j); //获得当前人的选择情况        }        cnt[temp]++; //对这个状态个数加一    }    for(int i=0;i<(1<<m);i++){// 遍历所有的状态        if(cnt[i]){ // 如果当前状态有人选择            addedge(S,i,cnt[i]);// 源点-》状态i 建边容量为选择当前状态的人数            for(int j=0;j<m;j++){                if(i&(1<<j))  // 遍历状态 i 中所有的 1                  addedge(i,j+T+1,inf);            }        }    }    for(int i=0;i<m;i++) {        int a;scanf("%d",&a);        addedge(i+T+1,T,a);  // 注意 星球的序号为 T+1开始,i是从0开始。     }}int vis[MAXN],dis[MAXN];int cur[MAXN];bool bfs(int st,int ed){    queue<int>Q;    memset(vis,0,sizeof(vis));    memset(dis,-1,sizeof(dis));    Q.push(st);vis[st]=1;dis[st]=1;    while(!Q.empty()){        int now=Q.front();Q.pop();        for(int i=head[now];i!=-1;i=edge[i].nexts){            Edge e=edge[i];            if(!vis[e.to]&&e.cap-e.flow>0){                vis[e.to]=1;                dis[e.to]=dis[now]+1;                if(e.to==ed) return 1;                Q.push(e.to);            }        }    }    return 0;}int dfs(int now,int a,int ed){    if(a==0||now==ed) return a;    int flow=0,f;    for(int &i=cur[now];i!=-1;i=edge[i].nexts){        Edge &e=edge[i];        if(dis[e.to]==dis[now]+1&&(f=dfs(e.to,min(e.cap-e.flow,a),ed))>0){            e.flow+=f;            flow+=f;            edge[i^1].flow-=f;            a-=f;            if(a==0) break;        }     }    return flow;}int max_flow(int st ,int ed){    int flow=0;    while(bfs(st,ed)){        memcpy(cur,head,sizeof(head));        flow+=dfs(st,inf,ed);    }    return flow;}int main(){  //  fread();//  fwrite();    while(scanf("%d%d",&n,&m)!=EOF){        init();        getmap();        int ans=max_flow(S,T);        if(ans!=n) puts("NO");        else puts("YES");    }    return 0;}

分析二 用多重匹配模板

#include<bits/stdc++.h>using namespace std;typedef pair<int,int>pii;#define first fi#define second se#define  LL long long#define fread() freopen("in.txt","r",stdin)#define fwrite() freopen("out.txt","w",stdout)#define CLOSE() ios_base::sync_with_stdio(false)const int MAXN = 1e5+10;const int MAXM = 10+7;const int mod = 1e9+7;const int inf = 0x3f3f3f3f;int uN,vN;int g[MAXN][MAXM];int link[MAXM][MAXN];bool vis[MAXM];int num[MAXM];void getmap(){    for(int i=0;i<uN;i++){        for(int j=0;j<vN;j++) {             int a;scanf("%d",&a);             g[i][j]=a;        }    }    for(int i=0;i<vN;i++) scanf("%d",&num[i]);}bool dfs(int u){    for(int v=0;v<vN;v++){        if(g[u][v]&&!vis[v]){            vis[v]=1;            if(link[v][0]<num[v]) {                link[v][++link[v][0]]=u;                return true;            }            for(int i=1;i<=num[0];i++){                if(dfs(link[v][i])) {                    link[v][i]=u;                    return true;                }            }        }    }    return false ;}int hungary(){    int res=0;    for(int i=0;i<vN;i++) link[i][0]=0;    for(int u=0;u<uN;u++){        memset(vis,0,sizeof(vis));        if(dfs(u)) res++;        else return 0;  // 没有加这句无限TLE 。     }    return res;}int main(){    CLOSE();//  fread();//  fwrite();    while(scanf("%d%d",&uN,&vN)!=EOF){        getmap();        if(hungary()!=uN) puts("NO");        else puts("YES");    }    return 0;}
原创粉丝点击