题意:n个人,m个星球,每个人给出对哪些星球感兴趣,每个星球给出能住的人数,求能否让所有人都住上感兴趣的星球。
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
题解:状压+最大流 | 二分图多重匹配
最大流做法:
n很大,直接最大流会t。
m最大为10,状态最多为1024,考虑状压,将每个人感兴趣的星球压缩成一个点,与源点建边,容量为感兴趣的星球数量。
每个状态与该状态所含的星球建边,容量为inf即可。
星球与汇点建边,容量为星球的最大人数。
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#include<fstream>
#include<set>
#include<map>
#include<sstream>
#include<iomanip>
#define ll long long
using namespace std;
//SAP邻接表形式 注意初始化
const int MAXN = 20010;
const int MAXM = 200010;
const int INF = 0x3f3f3f3f;
struct Node {
int to, next, cap;
}edge[MAXM];
int tol;
int head[MAXN];
int gap[MAXN], dis[MAXN], pre[MAXN], cur[MAXN];
void init() {
tol = 0;
memset(head, -1, sizeof(head));
}
void addedge(int u, int v, int w, int rw = 0) {
edge[tol].to = v; edge[tol].cap = w; edge[tol].next = head[u]; head[u] = tol++;
edge[tol].to = u; edge[tol].cap = rw; edge[tol].next = head[v]; head[v] = tol++;
}
int sap(int start, int end, int nodenum) {
memset(dis, 0, sizeof(dis));
memset(gap, 0, sizeof(gap));
memcpy(cur, head, sizeof(head));
int u = pre[start] = start, maxflow = 0, aug = -1;
gap[0] = nodenum;
while (dis[start] < nodenum) {
loop:
for (int& i = cur[u]; i != -1; i = edge[i].next) {
int v = edge[i].to;
if (edge[i].cap && dis[u] == dis[v] + 1) {
if (aug == -1 || aug > edge[i].cap)
aug = edge[i].cap;
pre[v] = u;
u = v;
if (v == end) {
maxflow += aug;
for (u = pre[u]; v != start; v = u, u = pre[u])
{
edge[cur[u]].cap -= aug;
edge[cur[u] ^ 1].cap += aug;
}
aug = -1;
}
goto loop;
}
}
int mindis = nodenum;
for (int i = head[u]; i != -1; i = edge[i].next) {
int v = edge[i].to;
if (edge[i].cap && mindis > dis[v]) {
cur[u] = i;
mindis = dis[v];
}
}
if ((--gap[dis[u]]) == 0)break;
gap[dis[u] = mindis + 1]++;
u = pre[u];
}
return maxflow;
}
int n, m, x, sum[1111];
int main() {
while (~scanf("%d%d", &n, &m)) {
init();
memset(sum, 0, sizeof(sum));
int flag = 1;
for (int i = 1; i <= n; i++) {
int tmp = 0;
for (int j = 1; j <= m; j++) {
scanf("%d", &x);
tmp = (tmp << 1) + x;
}
if (tmp == 0) flag = 1;
sum[tmp]++;
}
int tot = 0;
for (int i = 0; i < 1024; i++) {
if (!sum[i]) continue;
addedge(0, i + 1, sum[i]);
for (int j = 0; j < m; j++) {
if (i & (1 << j)) addedge(i + 1, 1024 + j + 1, sum[i]); //容量inf
}
}
for (int i = 1; i <= m; i++) {
scanf("%d", &x);
addedge(1024 + i, 1024 + m + 1, x);
}
if (sap(0, 1024 + m + 1, 1024 + m + 2) == n) puts("YES");
else puts("NO");
}
return 0;
}
二分图多重匹配做法:
套个板子就行。
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#include<fstream>
#include<set>
#include<map>
#include<sstream>
#include<iomanip>
#define ll long long
using namespace std;
//SAP邻接表形式 注意初始化
const int MAXN = 100010;
const int MAXM = 20;
int uN, vN;
int g[MAXN][MAXM];
int linker[MAXM][MAXN];
bool used[MAXM];
int num[MAXM];//右边最大的匹配数
bool dfs(int u) {
for (int v = 1; v <= vN; v++)
if (g[u][v] && !used[v]) {
used[v] = true;
if (linker[v][0] < num[v]) {
linker[v][++linker[v][0]] = u;
return true;
}
for (int i = 1; i <= num[v]; i++)
if (dfs(linker[v][i])) {
linker[v][i] = u;
return true;
}
}
return false;
}
bool hungary() {
int res = 0;
for (int i = 1; i <= vN; i++)
linker[i][0] = 0;
for (int u = 1; u <= uN; u++) {
memset(used, false, sizeof(used));
if (!dfs(u)) return false;
}
return true;
}
int n, m, x;
int main() {
while (~scanf("%d%d", &n, &m)) {
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]);
}
uN = n, vN = m;
if (hungary()) puts("YES");
else puts("NO");
}
return 0;
}