【最大流】Escape

https://www.bnuoj.com/v3/contest_show.php?cid=9149#problem/F

【题意】

给定n个人和m个星球,每个人可以匹配某些星球,每个星球有一定的容量限制,问能不能找出一种人和星球匹配的可行方案。

【思路】

裸的最大流。但人最多有1e5个,直接跑最大流会超时。但星球只有10个,所以一定有某些人对星球的选择是一模一样的,那么我们就可以状压缩点,缩到最多2^10=1024个。

【Accepted】

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<string>
  4 #include<cstring>
  5 #include<algorithm>
  6 #include<queue>
  7 using namespace std;
  8 const int maxn=1e5+20;
  9 const int maxm=1e6;
 10 const int inf=0x3f3f3f3f;
 11 
 12 struct Edge
 13 {
 14     int to,next,cap,flow;
 15 }edge[maxm];
 16 int tol;
 17 int head[maxn];
 18 int gap[maxn],dep[maxn],pre[maxn],cur[maxn];
 19 int num[1200];
 20 void init()
 21 {
 22     tol=0;
 23     memset(head,-1,sizeof(head));
 24     memset(num,0,sizeof(num));
 25 }
 26 
 27 void addedge(int u,int v,int w,int rw=0)
 28 {
 29     edge[tol].to=v;
 30     edge[tol].cap=w;
 31     edge[tol].next=head[u];
 32     edge[tol].flow=0;
 33     head[u]=tol++;
 34     edge[tol].to=u;
 35     edge[tol].cap=rw;
 36     edge[tol].next=head[v];
 37     edge[tol].flow=0;
 38     head[v]=tol++;
 39 }
 40 
 41 int sap(int start,int end,int N)
 42 {
 43     memset(gap,0,sizeof(gap));
 44     memset(dep,0,sizeof(dep));
 45     memcpy(cur,head,sizeof(head));
 46     int u=start;
 47     pre[u]=-1;
 48     gap[0]=N;
 49     int ans=0;
 50     while(dep[start]<N)
 51     {
 52         if(u==end)
 53         {
 54             int Min=inf;
 55             for(int i=pre[u];i!=-1;i=pre[edge[i^1].to])
 56             {
 57                 if(Min>edge[i].cap-edge[i].flow)
 58                 {
 59                     Min=edge[i].cap-edge[i].flow;
 60                 }
 61             }
 62             for(int i=pre[u];i!=-1;i=pre[edge[i^1].to])
 63             {
 64                 edge[i].flow+=Min;
 65                 edge[i^1].flow-=Min;
 66             }
 67             u=start;
 68             ans+=Min;
 69             continue;
 70         }
 71         bool flag=false;
 72         int v;
 73         for(int i=cur[u];i!=-1;i=edge[i].next)
 74         {
 75             v=edge[i].to;
 76             if(edge[i].cap-edge[i].flow&&dep[v]+1==dep[u])
 77             {
 78                 flag=true;
 79                 cur[u]=pre[v]=i;
 80                 break;
 81             }
 82         }
 83         if(flag)
 84         {
 85             u=v;
 86             continue;
 87         }
 88         int Min=N;
 89         for(int i=head[u];i!=-1;i=edge[i].next)
 90         {
 91             if(edge[i].cap-edge[i].flow&&dep[edge[i].to]<Min)
 92             {
 93                 Min=dep[edge[i].to];
 94                 cur[u]=i;
 95             }
 96         }
 97         gap[dep[u]]--;
 98         if(!gap[dep[u]])
 99         {
100             return ans;
101         }
102         dep[u]=Min+1;
103         gap[dep[u]]++;
104         if(u!=start)
105         {
106             u=edge[pre[u]^1].to;
107         }
108     }
109     return ans;
110 }
111 int a[maxn];
112 int n,m;
113 int bit[11];
114 
115 int main()
116 {
117     bit[0]=1;
118     for(int i=1;i<=10;i++)
119     {
120         bit[i]=bit[i-1]*2;
121     }
122     while(~scanf("%d%d",&n,&m))
123     {
124         init();
125         int x;
126         for(int i=1;i<=n;i++)
127         {
128             int temp=0;
129             for(int k=0;k<m;k++)
130             {
131                 scanf("%d",&x);
132                 if(x==1)
133                 {
134                     temp+=bit[k];
135                 }
136             }
137             num[temp]++;
138         }
139         int people=-inf;
140         for(int i=1024;i>=0;i--)
141         {
142             if(num[i])
143             {
144                 people=i;
145                 break;
146             }
147         }
148         int planet=people+1;
149         for(int i=0;i<=1024;i++)
150         {
151             if(num[i]==0)
152             {
153                 continue;
154             }
155             addedge(0,i,num[i]);
156             for(int k=0;k<m;k++)
157             {
158                 if(i&(1<<k))
159                 {
160                     addedge(i,planet+k,num[i]);
161                 }
162             }
163         }
164         for(int i=planet;i<planet+m;i++)
165         {
166             scanf("%d",&a[i]);
167             addedge(i,planet+m,a[i]);    
168         }
169         
170         if(num[0])
171         {
172             puts("NO");
173             continue;
174         }
175         int res=sap(0,planet+m,planet+m+1);
176         if(res==n)
177         {
178             puts("YES");
179         }
180         else
181         {
182             puts("NO");
183         }
184         getchar();
185     }
186     return 0;    
187 }
View Code
原文地址:https://www.cnblogs.com/itcsl/p/7133516.html