• 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 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

    在TLE n次之后,才反应过来,n太大了。。。

    百度之后才知道,需要用类似状态压缩的方法

    因为m<=10,所以状态数量只有1000左右,把每个会遇到的状态数的数量记录下来,从源点到左边的点拉容量为a[i]的边,左边的点到右边的点拉容量为INF的边,右边的点到汇点拉容量为ci的边

      1 #include<iostream>
      2 #include<cstring>
      3 #include<string>
      4 #include<cmath>
      5 #include<cstdio>
      6 #include<algorithm>
      7 #include<queue>
      8 #include<vector>
      9 #include<set>
     10 #define maxn 200005
     11 #define MAXN 200005
     12 #define mem(a,b) memset(a,b,sizeof(a))
     13 const int N=200005;
     14 const int M=200005;
     15 const int INF=0x3f3f3f3f;
     16 using namespace std;
     17 int n;
     18 struct Edge{
     19     int v,next;
     20     int cap,flow;
     21 }edge[MAXN*20];//注意这里要开的够大。。不然WA在这里真的想骂人。。问题是还不报RE。。
     22 int cur[MAXN],pre[MAXN],gap[MAXN],path[MAXN],dep[MAXN];
     23 int cnt=0;//实际存储总边数
     24 void isap_init()
     25 {
     26     cnt=0;
     27     memset(pre,-1,sizeof(pre));
     28 }
     29 void isap_add(int u,int v,int w)//加边
     30 {
     31     edge[cnt].v=v;
     32     edge[cnt].cap=w;
     33     edge[cnt].flow=0;
     34     edge[cnt].next=pre[u];
     35     pre[u]=cnt++;
     36 }
     37 void add(int u,int v,int w){
     38     isap_add(u,v,w);
     39     isap_add(v,u,0);
     40 }
     41 bool bfs(int s,int t)//其实这个bfs可以融合到下面的迭代里,但是好像是时间要长
     42 {
     43     memset(dep,-1,sizeof(dep));
     44     memset(gap,0,sizeof(gap));
     45     gap[0]=1;
     46     dep[t]=0;
     47     queue<int>q;
     48     while(!q.empty())
     49     q.pop();
     50     q.push(t);//从汇点开始反向建层次图
     51     while(!q.empty())
     52     {
     53         int u=q.front();
     54         q.pop();
     55         for(int i=pre[u];i!=-1;i=edge[i].next)
     56         {
     57             int v=edge[i].v;
     58             if(dep[v]==-1&&edge[i^1].cap>edge[i^1].flow)//注意是从汇点反向bfs,但应该判断正向弧的余量
     59             {
     60                 dep[v]=dep[u]+1;
     61                 gap[dep[v]]++;
     62                 q.push(v);
     63                 //if(v==sp)//感觉这两句优化加了一般没错,但是有的题可能会错,所以还是注释出来,到时候视情况而定
     64                 //break;
     65             }
     66         }
     67     }
     68     return dep[s]!=-1;
     69 }
     70 int isap(int s,int t)
     71 {
     72     if(!bfs(s,t))
     73     return 0;
     74     memcpy(cur,pre,sizeof(pre));
     75     //for(int i=1;i<=n;i++)
     76     //cout<<"cur "<<cur[i]<<endl;
     77     int u=s;
     78     path[u]=-1;
     79     int ans=0;
     80     while(dep[s]<n)//迭代寻找增广路,n为节点数
     81     {
     82         if(u==t)
     83         {
     84             int f=INF;
     85             for(int i=path[u];i!=-1;i=path[edge[i^1].v])//修改找到的增广路
     86                 f=min(f,edge[i].cap-edge[i].flow);
     87             for(int i=path[u];i!=-1;i=path[edge[i^1].v])
     88             {
     89                 edge[i].flow+=f;
     90                 edge[i^1].flow-=f;
     91             }
     92             ans+=f;
     93             u=s;
     94             continue;
     95         }
     96         bool flag=false;
     97         int v;
     98         for(int i=cur[u];i!=-1;i=edge[i].next)
     99         {
    100             v=edge[i].v;
    101             if(dep[v]+1==dep[u]&&edge[i].cap-edge[i].flow)
    102             {
    103                 cur[u]=path[v]=i;//当前弧优化
    104                 flag=true;
    105                 break;
    106             }
    107         }
    108         if(flag)
    109         {
    110             u=v;
    111             continue;
    112         }
    113         int x=n;
    114         if(!(--gap[dep[u]]))return ans;//gap优化
    115         for(int i=pre[u];i!=-1;i=edge[i].next)
    116         {
    117             if(edge[i].cap-edge[i].flow&&dep[edge[i].v]<x)
    118             {
    119                 x=dep[edge[i].v];
    120                 cur[u]=i;//常数优化
    121             }
    122         }
    123         dep[u]=x+1;
    124         gap[dep[u]]++;
    125         if(u!=s)//当前点没有增广路则后退一个点
    126         u=edge[path[u]^1].v;
    127      }
    128      return ans;
    129 }
    130 
    131 int a[maxn];
    132 
    133 int main(){
    134     int m,s,t;
    135     while(~scanf("%d %d",&n,&m)){
    136         int b,c;
    137         memset(a,0,sizeof(a));
    138         int Max=0;
    139         isap_init();
    140         for(int i=1;i<=n;i++){
    141             int tmp=0;
    142             for(int j=1;j<=m;j++){
    143                 scanf("%d",&c);
    144                 tmp=(tmp<<1)|c;
    145             }
    146             if(Max<tmp) Max=tmp;
    147             a[tmp]++;
    148         }
    149         s=0,t=Max+m+1;
    150         for(int i=1;i<=m;i++){
    151             scanf("%d",&c);
    152             add(Max+i,t,c);
    153         }
    154         for(int i=1;i<=Max;i++){
    155             if(a[i]>0){
    156                 add(s,i,a[i]);
    157                 int k=m,p=i;
    158                 while(k&&p){
    159                     int tmp=p%2;
    160                     p/=2;
    161                     if(tmp>0) add(i,Max+k,INF);
    162                     k--;
    163                 }
    164             }
    165         }
    166         int tmp=n;
    167         n=Max+m+2;
    168         int ans=isap(s,t);
    169         if(ans==tmp) puts("YES");
    170         else puts("NO");
    171     }
    172 }
    View Code
  • 相关阅读:
    web自动化框架如何设计
    如何保证元素定位的成功率(等待机制)
    验证码问题处理
    selenium元素定位
    网路知识总结(session&&Cookie&&三次握手&&请求头)
    python中方法的总结
    Twelve Day 检测大写字母
    超过5名学生的课(SQL语句)
    The Eleven Day 删除排序数组中的重复项
    删除重复的电子邮箱(SQL语句)
  • 原文地址:https://www.cnblogs.com/Fighting-sh/p/9951520.html
Copyright © 2020-2023  润新知