1. 程式人生 > >HDU3605: Escape-二進制優化建圖-最大流

HDU3605: Escape-二進制優化建圖-最大流

tro 分享 strong to do truct void 最大流 cst star

目錄

  • 目錄
  • 思路:

(有任何問題歡迎留言或私聊 && 歡迎交流討論哦

目錄

題意:傳送門

?原題目描述在最下面。
?\(n(n\leq 100000)\)個人\(m(m\leq 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<<"\n"
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\n");
    else printf("NO\n");
  }
  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

技術分享圖片

HDU3605: Escape-二進制優化建圖-最大流