HDU3605: Escape-二进制优化建图-最大流

(有任何问题欢迎留言或私聊 && 欢迎交流讨论哦

目录

题意:传送门

 原题目描述在最下面。
(n(nleq 100000))个人(m(mleq 10))个星球,每个星球容纳的人数有上限,每个人都有自己想去的星球意愿。问是否所有的都能去到外星球。

思路:

 肯定不能暴力建图,因为人太多了。注意到m的大小只有10。刷过状压dp的人应该都能想到要二进制优化。
 这是每个人其实都是没有区别的,有区别的只是他们的意愿。然后最多也只有(2^{10} =1024)种意愿。那就把这些当作(1000)多个点嘛。记录每种状态的人数。

  • 超级源点S向每个星球连边,边容量为星球限值。
  • 每个星球向对它有意愿的人点连边,流量为这些人的数量,这个我们之前预处理出来了。
  • 然后(2^m)的状态点向超级汇点连边,流量为此状态的人数。

细节见代码。

AC代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#define mme(a,b) memset((a),(b),sizeof((a)))  
#define fuck(x) cout<<"* "<<x<<"
"
using namespace std;
typedef long long LL;
const int INF = 0x3f3f3f3f;
const int MXN = 1e4+7;
const int MXE = 1e7+7;
struct DINIC{
  int tot,vt,vs;
  int d[MXN],head[MXN];
  struct lp{
    int to,w,nex;
  }cw[MXE];
  void add_edge(int a,int b,int c){
    cw[++tot].to=b;cw[tot].nex=head[a],cw[tot].w=c;
    head[a]=tot;
    cw[++tot].to=a;cw[tot].nex=head[b],cw[tot].w=0;
    head[b]=tot;
  }
  bool bfs(){
    memset(d,-1,sizeof(d));
    queue<int>Q;
    Q.push(vt);d[vt]=0;
    while(!Q.empty()){
      int u=Q.front();
      Q.pop();
      for(int i=head[u];i!=-1;i=cw[i].nex){
        int v=cw[i].to;
        if(cw[i^1].w&&d[v]==-1){
          d[v]=d[u]+1;
          Q.push(v);
        }
      }
    }
    return d[vs]!=-1;
  }
  int dfs(int x,int f){
    if(x==vt||f==0) return f;
    int use=0,w;
    for(int i=head[x];i!=-1;i=cw[i].nex){
      int to=cw[i].to;
      if(d[to]==d[x]-1 && cw[i].w){
        w=dfs(to,min(cw[i].w,f-use));
        cw[i].w-=w,cw[i^1].w+=w;
        use+=w;
        if(use==f) return f;
      }
    }
    return use;
  }
  void init(int st,int ed){
    tot=-1;
    memset(head,-1,sizeof(head));
    vs=st;vt=ed;
  }
  int max_flow(){
    int ans=0;
    while(bfs())ans+=dfs(vs,INF);
    return ans;
  }
}dinic;
int n, m;
int vs, vt;
int num[1<<11];
int main(){
  while(~scanf("%d%d",&n,&m)){
    int state = 1<<m;
    mme(num,0);
    vs=state+m+1,vt=state+m+2;
    dinic.init(vs,vt);
    for(int i=1;i<=n;++i){
      int tmp=0;
      for(int j=1;j<=m;++j){
        int x;scanf("%d",&x);
        if(x)tmp|=(1<<(j-1));
      }
      num[tmp]++;
    }
    for(int i=1;i<=m;++i){
      int x;scanf("%d",&x);
      dinic.add_edge(vs,i+state,x);
    }
    for(int i=1;i<state;++i){
      if(num[i]==0)continue;
      dinic.add_edge(i,vt,num[i]);
      for(int j=0;j<m;++j){
        if(i&(1<<j)){
          dinic.add_edge(state+j+1,i,num[i]);
        }
      }
    }
    LL ans = dinic.max_flow();
    if(ans>=n)printf("YES
");
    else printf("NO
");
  }
  return 0;
}


####原题目描述: 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

Recommend
lcy

这里写图片描述

原文地址:https://www.cnblogs.com/Cwolf9/p/9418994.html