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:
代码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;
}
继续加油~
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;
}
继续加油~
相关文章推荐
- 【HDU - 3605 】Escape 【状态压缩 构图+最大流 or 多重匹配】
- HDU 3605 Escape(最大流+状态压缩)
- Escape HDU - 3605 (最大流)(多重匹配)
- HDU 3605 Escape(最大流+状态压缩)
- hdu 3605 Escape (最大流+状态压缩)
- hdu 3605 Escape【图论-网络流-最大流-状态压缩】
- HDU 3605 Escape(状态压缩+最大流)
- hdu_3605 Escape 二分图的多重匹配 匈牙利算法
- HDU - 3605 Escape(最大流+状态压缩)
- hdu 3605 Escape 二分图的多重匹配(匈牙利算法)
- HDU 3605 —— Escape 状态压缩+最大流
- hdu 3605 Escape 二分图的多重匹配(匈牙利算法)
- hdu 3605 Escape 状态压缩+最大流
- hdu 3605 Escape【状态压缩+最大流Dinic+建图】
- HDU 3605 Escape(最大流+状态压缩)
- hdu 1054 Strategic Game(模板) 最大二分匹配,最小点覆盖 匈牙利算法
- HDU 3605 Escape 【二分匹配之多重匹配】
- HDU 2063 过山车 【匈牙利算法,二分图最大匹配】
- hdu 2063 最大二分匹配,匈牙利算法
- HDU 3605 最大流+状态压缩