您的位置:首页 > 其它

HDU-3605 Escape(状态压缩+最大流求多重匹配、改版匈牙利算法)

2017-10-04 20:07 381 查看
题意:

n个人,m个星球,每个人只愿意往特定的星球搬迁,而每个星球有一个最大允许居住数量。问能否将每个人都安排好居住的星球。(n <= 1e5, m <= 10)

思路:

其实就是裸的二分图的多重匹配,但是由于n较大,直接做肯定会超时。但发现m较小,所以我们先通过m将所有人的状态压缩成2^10个,然后用网络流就可以做了。

还有一种改版的匈牙利做法。即我们记录一下被匹配的点(即B部的点)已经匹配了多少个点,它能够匹配的最大数量就是它的上限。如果此时不足上限,那么就直接匹配成功并记录下来,如果达到上限,那么我们就像匈牙利最初的算法那样去尝试已经匹配了这个点的所有的点能否去匹配新的点。如此递归,由于m很小,所以最深顶多达到m个深度,即复杂度为O(n*m);

代码1:

#include <algorithm>
#include <iostream>
#include <string.h>
#include <cstdio>
#include <queue>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 1100;
const int maxm = 25000;
struct node{int w; int v, next;} edge[maxm];
int pre[maxn], rec[maxn], head[maxn], gap[maxn], now[maxn];
int dis[maxn];
int t, n, m, no, up;
int S, T;
queue<int> q;
inline void add(int u, int v, int w)
{
edge[no].v = v; edge[no].w = w;
edge[no].next = head[u]; head[u] = no++;
edge[no].v = u; edge[no].w = 0;
edge[no].next = head[v]; head[v] = no++;
}
inline void pre_init()
{
no = 0;
memset(head, -1, sizeof head);
}
void init(int S, int T)
{
memset(gap, 0, sizeof gap);
memset(dis, 0x3f, sizeof dis);
for(int i = 0; i <= up; ++i)
now[i] = head[i];
while(!q.empty()) q.pop();
dis[T] = 0; q.push(T);
while(!q.empty())
{
int tp = q.front(); q.pop();
++gap[dis[tp]];
int k = head[tp];
while(k != -1)
{
if(dis[edge[k].v] == inf && edge[k^1].w)
{
dis[edge[k].v] = dis[tp]+1;
q.push(edge[k].v);
}
k = edge[k].next;
}
}
}
int SAP(int S, int T)
{
int ans = 0, flow = inf;
int top = S;
pre[S] = S; init(S, T);
while(dis[S] < up)
{
if(top == T)
{
ans += flow;
while(top != S)
{
edge[rec[top]].w -= flow;
edge[rec[top]^1].w += flow;
top = pre[top];
}
flow = inf;
}
int k = now[top];
while(k != -1)
{
int v = edge[k].v;
if(edge[k].w && dis[top] == dis[v]+1)
{
flow = min(flow, edge[k].w);
pre[v] = top; rec[v] = k;
now[top] = k; top = v;
break;
}
k = edge[k].next;
}
if(k == -1)
{
int mind = up;
if(--gap[dis[top]] == 0) break;
int k = now[top] = head[top];
while(k != -1)
{
if(edge[k].w && mind>dis[edge[k].v]) mind = dis[edge[k].v];
k = edge[k].next;
}
++gap[dis[top] = mind+1];
top = pre[top];
}
}
return ans;
}
int dig[1<<10];
void mapping()
{
int x, a, b;
memset(dig, 0, sizeof dig);
for(int i = 1; i <= n; ++i)
{
int t = 0;
for(int j = 0; j < m; ++j)
{
scanf("%d", &x);
if(x) t += (1<<j);
}
++dig[t];
}
for(int i = 0; i < (1<<10); ++i)
{
if(!dig[i]) continue;
add(S, i, dig[i]);
int t = i, k = 0;
while(t)
{
++k;
if(t&1) add(i, (1<<10)+k, dig[i]);
t >>= 1;
}
}
for(int i = 1; i <= m; ++i)
{
scanf("%d", &x);
add((1<<10)+i, T, x);
}
}
int main()
{
while(scanf("%d %d", &n, &m) != EOF)
{
up = (1<<10)+12, S = 1035, T = 1036;
pre_init();
mapping();
if(SAP(S, T) == n) puts("YES");
else puts("NO");
}
return 0;
}


代码2:

#include <bits/stdc++.h>
using namespace std;
bool G[100005][15];
int match[15][100005];
int vis[15];
int hav[15], maxx[15], cun[15][100005];
int n, m;
bool dfs(int u)
{
for(int i = 1; i <= m; ++i)
{
if(!G[u][i] || vis[i]) continue;
vis[i] = 1;
if(hav[i] < maxx[i])
{
cun[i][++hav[i]] = u;
return true;
}
else
{
for(int j = 1; j <= hav[i]; ++j)
if(dfs(cun[i][j]))
{
cun[i][hav[i]] = u;
return true;
}
}
}
return false;
}
bool work()
{
memset(hav, 0, sizeof hav);
for(int i = 1; i <= n; ++i)
{
memset(vis, 0, sizeof vis);
if(!dfs(i)) return false;
}
return true;
}
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", &maxx[i]);
if(work()) puts("YES");
else puts("NO");
}
return 0;
}

继续加油~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: