题目链接:Click here~~
题意:
有 n 个人选择 m 个星球居住,选择情况和星球居住上限有限制,问是否能全部满足要求。
解题思路:
解法一:
开始想到了最裸的建图,果然 TLE 了。
由于 n 太大(1e5) m 很小(10),所以我们可以进行状态压缩,将 n 个人等价划分成 1 << m 个集合,记录下各个集合有多少人。
建边:S -> mask,cap = cnt[mask] ; mask -> planet of mask,cap = inf;planet -> T,cap = limit of planet。
#include <queue>
#include <stdio.h>
#include <string.h>
#include <algorithm>
const int inf = 0x3fffffff;
using namespace std;
#define CLR(a,v) memset(a,v,sizeof(a))
template<int N,int M>
struct Isap{
int top,s,t,d[N],pre[N],cur[N],gap[N];
struct Vertex{
int head;
}V[N];
struct Edge{
int v,next;
int c,f;
}E[M];
inline void init(){
CLR(V,-1);
top = 0;
}
inline void set_st(int _s,int _t){
s = _s , t = _t;
}
inline void add_edge(int u,int v,int c){
E[top].v = v;
E[top].c = c;E[top].f = 0;
E[top].next = V[u].head;
V[u].head = top++;
}
inline void add(int u,int v,int c){
add_edge(u,v,c);
add_edge(v,u,0);
}
inline void set_d(){
CLR(d,-1);CLR(gap,0);
queue<int> Q;
d[t] = 0;
Q.push(t);
while(!Q.empty()){
int v = Q.front();
Q.pop();
++gap[ d[v] ];
for(int i=V[v].head;~i;i=E[i].next){
int u = E[i].v;
if(d[u] == -1){
d[u] = d[v] + 1;
Q.push(u);
}
}
}
}
int sap(int n){ //n vertexs
set_d();
int ans = 0, u = s, flow = inf;
memcpy(cur,V,sizeof(V));
while(d[s] < n){
int &i = cur[u];
for(;~i;i=E[i].next){
int v = E[i].v;
if(E[i].c>E[i].f && d[u]==d[v]+1){
u = v;
pre[v] = i;
flow = min(flow,E[i].c-E[i].f);
if(u == t){
while(u != s){
int j = pre[u];
E[j].f += flow;
E[j^1].f -= flow;
u = E[j^1].v;
}
ans += flow;
flow = inf;
}
break;
}
}
if(i == -1){
if(--gap[ d[u] ] == 0)
break;
int dmin = n - 1;
cur[u] = V[u].head;
for(int j=V[u].head;~j;j=E[j].next)
if(E[j].c > E[j].f)
dmin = min(dmin,d[ E[j].v ]);
d[u] = dmin + 1;
++gap[ d[u] ];
if(u != s)
u = E[ pre[u]^1 ].v;
}
}
return ans;
}
};
const int N = 1<<10 | 25;
Isap<N,N*11*2+5> g;
int cnt[1<<10];
inline void In(int& res)
{
int c;
while((c = getchar())<'0' || c>'9');
res = c-'0';
while((c = getchar())>='0' && c<='9')
res = res*10 + c-'0';
}
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
CLR(cnt,0);
g.init();
for(int i=1;i<=n;i++)
{
int mask = 0;
for(int j=0;j<m;j++)
{
int can;
//scanf("%d",&can);
In(can);
if(can)
mask |= 1 << j;
}
cnt[mask]++;
}
int nn = n;
n = 1 << m;
for(int mask=1;mask<n;mask++)
if(cnt[mask])
{
g.add(0,mask,cnt[mask]);
for(int j=0;j<m;j++)
if(mask & (1 << j))
g.add(mask,n+j,inf);
}
for(int i=0;i<m;i++)
{
int cap;
//scanf("%d",&cap);
In(cap);
if(cap)
g.add(n+i,n+m,cap);
}
g.set_st(0,n+m);
int ans = cnt[0] ? 0 : g.sap(n+m+1);
puts(ans==nn?"YES":"NO");
}
return 0;
}
#include <vector>
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
const int N = 1e5 + 5;
const int M = 12;
bool g[N][M],vis[M];
int n,m,match[M][N],cap[M],cnt[M];
bool dfs(int u)
{
for(int v=1;v<=m;v++)
{
if(!vis[v] && g[u][v])
{
vis[v] = true;
if(cnt[v] < cap[v])
{
match[v][ ++cnt[v] ] = u;
return true;
}
else
{
for(int i=1;i<=cap[v];i++)
{
if(dfs(match[v][i]))
{
match[v][i] = u;
return true;
}
}
}
}
}
return false;
}
int maxMatch(int n)
{
memset(match,0,sizeof(match));
memset(cnt,0,sizeof(cnt));
int ans = 0;
for(int i=1;i<=n;i++)
{
memset(vis,false,sizeof(vis));
if(dfs(i))
++ans;
else
return 0;
}
return ans;
}
inline void In(int& res)
{
int c;
while((c = getchar())<'0' || c>'9');
res = c-'0';
while((c = getchar())>='0' && c<='9')
res = res*10 + c-'0';
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
memset(g,false,sizeof(g));
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
int can;
//scanf("%d",&can);
In(can);
g[i][j] = can;
}
}
for(int i=1;i<=m;i++)
{
//scanf("%d",&cap);
In(cap[i]);
}
puts(maxMatch(n)==n?"YES":"NO");
}
return 0;
}