HDU-3605 Escape(最大流,状态压缩)

题目链接:HDU-3605 Escape

题意

地球上有$n(1\leq n \leq 100000)$个人需要移居到$m(1\leq m \leq 10)$个外星球上,每个人只有特定的若干个外星球可供选择,每个外星球有接受移居的人数上限,问能否让所有人移居成功。

思路


由于$n$的范围有$1e5$,直接建图的话边可能达到$1e6$条,跑最大流会超时。

考虑到$m$最大只有$10$,每个人可选择的若干星球最多只有$2^{10}$种可能的状态,所以实际上当$n$比较大时,很多人可选择的若干个星球是一样的。我们可以用二进制状态压缩来表示一种可选星球的状态,统计出这种状态的人数,以状态为结点,就不用每个人用一个结点表示。

用$s$和$t$分别表示源点、汇点,$(始点,终点,容量)$表示一条边,建图如下:

对于每一个状态,连边$(s,状态,可选星球是这个状态的人数)$;

对于一个状态中可选择的每一个星球,连边$(状态,星球,无穷大)$;

对于每一个星球,连边$(星球,t,星球的人数上限)$。

最大流就是能成功移居的最大人数。


代码实现

![]()![]() ```

include

include

include

include

using std::queue;
const int INF = 0x3f3f3f3f, N = 2000, M = 30000;
int head[N], d[N], cnt[N];
int s, t, tot, maxflow;
struct Edge
{
int to, cap, nex;
} edge[M];
queue q;
void add(int x, int y, int z) {
edge[++tot].to = y, edge[tot].cap = z, edge[tot].nex = head[x], head[x] = tot;
edge[++tot].to = x, edge[tot].cap = 0, edge[tot].nex = head[y], head[y] = tot;
}
bool bfs() {
memset(d, 0, sizeof(d));
while (q.size()) q.pop();
q.push(s); d[s] = 1;
while (q.size()) {
int x = q.front(); q.pop();
for (int i = head[x]; i; i = edge[i].nex) {
int v = edge[i].to;
if (edge[i].cap && !d[v]) {
q.push(v);
d[v] = d[x] + 1;
if (v == t) return true;
}
}
}
return false;
}
int dinic(int x, int flow) {
if (x == t) return flow;
int rest = flow, k;
for (int i = head[x]; i && rest; i = edge[i].nex) {
int v = edge[i].to;
if (edge[i].cap && d[v] == d[x] + 1) {
k = dinic(v, std::min(rest, edge[i].cap));
if (!k) d[v] = 0;
edge[i].cap -= k;
edge[i^1].cap += k;
rest -= k;
}
}
return flow - rest;
}
void init(int n) {
tot = 1, maxflow = 0;
s = n, t = s + 1;
memset(head, 0, sizeof(head));
memset(cnt, 0, sizeof(cnt));
}

int main() {
int n, m;
while (~scanf("%d %d", &n, &m)) {
init(1024 + m);
for (int i = 0, sta = 0; i < n; i++, sta = 0) {
for (int j = 0, ok; j < m; j++) {
scanf("%d", &ok);
sta = sta * 2 + ok;
}
if (!cnt[sta]) for (int j = m - 1; j >= 0; j--) {
if ((sta >> j) & 1) add(sta, 1023 + m - j, INF);
}
cnt[sta]++;
}
for (int i = 0; i < 1024; i++) if (cnt[i]) add(s, i, cnt[i]);
for (int i = 0, num; i < m; i++) {
scanf("%d", &num);
add(i + 1024, t, num);
}
while (bfs()) maxflow += dinic(s, INF);
if (maxflow >= n) puts("YES");
else puts("NO");
}
return 0;
}



 View Code

声明:该文章系转载,转载该文章的目的在于更广泛的传递信息,并不代表本网站赞同其观点,文章内容仅供参考。

本站是一个个人学习和交流平台,网站上部分文章为网站管理员和网友从相关媒体转载而来,并不用于任何商业目的,内容为作者个人观点, 并不代表本网站赞同其观点和对其真实性负责。

我们已经尽可能的对作者和来源进行了通告,但是可能由于能力有限或疏忽,导致作者和来源有误,亦可能您并不期望您的作品在我们的网站上发布。我们为这些问题向您致歉,如果您在我站上发现此类问题,请及时联系我们,我们将根据您的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。