https://vjudge.net/problem/HDU-3605
这道题直接最大流就爆了,蠢的我没算复杂度,后来回过神时间复杂度是O(V^2*E)...\
百度正确做法:状压缩点,因为最多只有十个星球,对于每个人他都有至多1024(2^10)种可能的选择,因此可以把这1e5个点缩成1024个点,点权重复的用从源点到该点的流量进行管理,有几个点就设置流量为几,啊好神奇,顺便学一下二分图多重匹配吧(好像没什么用,不就是最大流??)
二分图多重匹配
适用于二分图,多重匹配的问题,匈牙利算法
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<cmath>
#define ll long long
#define mod 1000000007
#define inf 0x3f3f3f3f
using namespace std;
const int maxn = 100005;
const int maxm = 15;
bool vis[maxm];
int g[maxn][maxm];
int link[maxm][maxn];
int num[maxm];
int n, m;
bool dfs(int u)
{
for(int v = 1; v <= m; v ++)
{
if(g[u][v] && ! vis[v])
{
vis[v] = 1;
if(link[v][0] < num[v])
{
link[v][++ link[v][0]] = u;
return 1;
}
for(int i = 1; i <= num[v]; i ++)
{
if(dfs(link[v][i]))
{
link[v][i] = u;
return 1;
}
}
}
}
return 0;
}
int main()
{
while(scanf("%d%d", &n, &m) != EOF)
{
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= m; j ++)
scanf("%d", &g[i][j]);
for(int i = 1; i <= m; i ++)
scanf("%d", &num[i]);
bool flag = 1;
memset(link, 0, sizeof(link));
for(int u = 1; u <= n; u ++)
{
memset(vis, 0, sizeof(vis));
if(! dfs(u))
{
flag = 0;
break;
}
}
if(flag) printf("YES\n");
else printf("NO\n");
}
return 0;
}
最大流+缩点
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<cmath>
#define ll long long
#define mod 1000000007
#define inf 0x3f3f3f3f
using namespace std;
const int maxn = 2005;
const int maxm = 15;
int cnt, st, en;
int n, m;
int N;
int u, v, w;
int num[maxn];
struct node
{
int to, next, w;
}e[maxn*maxm];
int head[maxn], depth[maxn], cur[maxn];
void init()
{
//st = 1, en = n;
cnt = 0;
memset(head, -1, sizeof(head));
memset(num, 0, sizeof(num));
}
void addedge(int u, int v, int w)
{
e[cnt].w = w;
e[cnt].to = v;
e[cnt].next = head[u];
head[u] = cnt ++;
e[cnt].w = 0;
e[cnt].to = u;
e[cnt].next = head[v];
head[v] = cnt ++;
}
int dfs(int u, int flow)
{
if(u == en) return flow;
for(int& i = cur[u]; ~i; i = e[i].next)
{
if(depth[e[i].to] == depth[u] + 1 && (e[i].w != 0))
{
int zen = dfs(e[i].to, min(e[i].w, flow));
if(zen)
{
e[i].w -= zen;
e[i^1].w += zen;
return zen;
}
}
}
return 0;
}
int bfs()
{
queue<int> q;
while(! q.empty()) q.pop();
memset(depth, 0, sizeof(depth));
depth[st] = 1;
q.push(st);
while(! q.empty())
{
int h = q.front();
q.pop();
for(int i = head[h]; ~i; i = e[i].next)
{
if((! depth[e[i].to]) && e[i].w)
{
depth[e[i].to] = depth[h] + 1;
q.push(e[i].to);
}
}
}
if(depth[en]) return 1;
return 0;
}
int dinic()
{
int ans = 0;
while(bfs())
{
for(int i = 0; i <= N; i ++)
cur[i] = head[i];
while(int d = dfs(st, inf))
ans += d;
}
return ans;
}
int main()
{
while(scanf("%d%d", &n, &m) != EOF)
{
init();
int w;
int tmp;
for(int i = 1; i <= n; i ++)
{
tmp = 0;
for(int j = 1; j <= m; j ++)
{
scanf("%d", &w);
tmp = tmp * 2 + w;
}
num[tmp] ++;
}
tmp = 0;
for(int i = 1; i <= 1024; i ++)
{
if(num[i])
tmp ++;
}
N = tmp + m + 1;
st = 0, en = N;
// for(int i = 1; i <= tmp; i ++)
// addedge(0, i, num[i]);
int now = 0;
for(int i = 1; i <= 1024; i ++)
{
if(num[i])
{
now ++;
addedge(0, now, num[i]);
int top = m;
int x = i;
while(x)
{
if(x & 1) addedge(now, tmp+top, inf);
top --;
x /= 2;
}
}
}
int tmp1;
for(int i = 1; i <= m; i ++)
{
scanf("%d", &tmp1);
addedge(tmp + i, N, tmp1);
}
//cout<<st<<' '<<tmp<< ' '<<en<<endl;
int ans = dinic();
if(ans >= n) printf("YES\n");
else printf("NO\n");
}
return 0;
}