[ZJOI2009] 假期的宿舍 - 最大流
作者:互联网
[ZJOI2009] 假期的宿舍
Description
每个人只能睡和自己直接认识的人的床,有 \(n\) 个人,每个人可能是在校学生或者不是,可能回家也可能不回,判断是否存在一个方案使得不回家的在校学生和非本校学生都有地方住。
Solution
二分图匹配,人 \(i\) 和人 \(j\) 如果认识,那么人 \(i\) 就和床 \(j\) 连边。注意人 \(i\) 和床 \(i\) 之间要额外连边。如果 \(i\) 是本校学生,那么床 \(i\) 和汇点之间连边;如果 \(i\) 不是在校学生或者 \(i\) 不回家,那么源点和人 \(i\) 之间连边,表示他需要一张床。
编号分配:源点 \(1\),汇点 \(2\),第 \(i\) 个人编号 \(3+i\),第 \(i\) 个人对应的床(假设存在,如果没有这张床那么就不和汇点连边)编号为 \(3+n+i\)。
#include <bits/stdc++.h>
using namespace std;
#define int long long
#ifndef __FLOW_HPP__
#define __FLOW_HPP__
#include <bits/stdc++.h>
using namespace std;
#define int long long
namespace flowsolution
{
const int N = 1005;
const int M = 10005;
const int inf = 1e+12;
struct MaxflowSolution
{
int *dis, ans, cnt = 1, s, t, *pre, *next, *head, *val;
MaxflowSolution()
{
cnt = 1;
dis = new int[N];
pre = new int[M];
next = new int[M];
head = new int[N];
val = new int[M];
fill(dis, dis + N, 0);
fill(pre, pre + M, 0);
fill(next, next + M, 0);
fill(head, head + N, 0);
fill(val, val + M, 0);
}
~MaxflowSolution()
{
delete[] dis;
delete[] pre;
delete[] next;
delete[] head;
delete[] val;
}
std::queue<int> q;
void make(int x, int y, int z)
{
pre[++cnt] = y, next[cnt] = head[x], head[x] = cnt, val[cnt] = z;
pre[++cnt] = x, next[cnt] = head[y], head[y] = cnt;
}
bool bfs()
{
fill(dis, dis + N, 0);
q.push(s), dis[s] = 1;
while (!q.empty())
{
int x = q.front();
q.pop();
for (int i = head[x]; i; i = next[i])
if (!dis[pre[i]] && val[i])
dis[pre[i]] = dis[x] + 1, q.push(pre[i]);
}
return dis[t];
}
int dfs(int x, int flow)
{
if (x == t || !flow)
return flow;
int f = flow;
for (int i = head[x]; i; i = next[i])
if (val[i] && dis[pre[i]] > dis[x])
{
int y = dfs(pre[i], min(val[i], f));
f -= y, val[i] -= y, val[i ^ 1] += y;
if (!f)
return flow;
}
if (f == flow)
dis[x] = -1;
return flow - f;
}
int solve(int _s, int _t)
{
s = _s;
t = _t;
ans = 0;
for (; bfs(); ans += dfs(s, inf));
return ans;
}
};
struct CostflowSolution
{
struct Edge
{
int p = 0, c = 0, w = 0, next = -1;
} * e;
int s, t, tans, ans, cost, ind, *bus, qhead = 0, qtail = -1, *qu, *vis, *dist;
CostflowSolution()
{
e = new Edge[M];
qu = new int[M];
bus = new int[N];
vis = new int[N];
dist = new int[N];
fill(qu, qu + M, 0);
fill(bus, bus + N, 0);
fill(vis, vis + N, 0);
fill(dist, dist + N, 0);
ind = 0;
}
~CostflowSolution()
{
delete[] e;
delete[] qu;
delete[] vis;
delete[] dist;
}
void graph_link(int p, int q, int c, int w)
{
e[ind].p = q;
e[ind].c = c;
e[ind].w = w;
e[ind].next = bus[p];
bus[p] = ind;
++ind;
}
void make(int p, int q, int c, int w)
{
graph_link(p, q, c, w);
graph_link(q, p, 0, -w);
}
int dinic_spfa()
{
qhead = 0;
qtail = -1;
fill(vis, vis + N, 0);
fill(dist, dist + N, inf);
vis[s] = 1;
dist[s] = 0;
qu[++qtail] = s;
while (qtail >= qhead)
{
int p = qu[qhead++];
vis[p] = 0;
for (int i = bus[p]; i != -1; i = e[i].next)
if (dist[e[i].p] > dist[p] + e[i].w && e[i].c > 0)
{
dist[e[i].p] = dist[p] + e[i].w;
if (vis[e[i].p] == 0)
vis[e[i].p] = 1, qu[++qtail] = e[i].p;
}
}
return dist[t] < inf;
}
int dinic_dfs(int p, int lim)
{
if (p == t)
return lim;
vis[p] = 1;
int ret = 0;
for (int i = bus[p]; i != -1; i = e[i].next)
{
int q = e[i].p;
if (e[i].c > 0 && dist[q] == dist[p] + e[i].w && vis[q] == 0)
{
int res = dinic_dfs(q, min(lim, e[i].c));
cost += res * e[i].w;
e[i].c -= res;
e[i ^ 1].c += res;
ret += res;
lim -= res;
if (lim == 0)
break;
}
}
return ret;
}
pair<int, int> solve(int _s, int _t)
{
s = _s;
t = _t;
ans = 0;
cost = 0;
while (dinic_spfa())
{
fill(vis, vis + N, 0);
ans += dinic_dfs(s, inf);
}
return make_pair(ans, cost);
}
};
} // namespace flowsolution
#endif
void solve()
{
int n;
cin >> n;
vector<int> is_student(n + 2);
vector<int> is_away(n + 2);
vector<vector<int>> is_related(n + 2, vector<int>(n + 2));
for (int i = 1; i <= n; i++)
cin >> is_student[i];
for (int i = 1; i <= n; i++)
cin >> is_away[i];
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
cin >> is_related[i][j];
int S = 1, T = 2;
auto id_person = [&](int i) -> int {
return i + 3;
};
auto id_bed = [&](int i) -> int {
return i + n + 3;
};
flowsolution::MaxflowSolution flow;
int tot = 0;
for (int i = 1; i <= n; i++)
if (is_student[i])
flow.make(id_bed(i), T, 1);
for (int i = 1; i <= n; i++)
if (!is_student[i] || !is_away[i])
flow.make(S, id_person(i), 1), ++tot;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
if (i == j || is_related[i][j])
flow.make(id_person(i), id_bed(j), 1);
cout << (flow.solve(S, T) == tot ? "^_^" : "T_T") << endl;
}
signed main()
{
// ios::sync_with_stdio(false);
int t;
cin >> t;
while (t--)
{
solve();
}
}
标签:dist,vis,假期,next,int,宿舍,ZJOI2009,fill,dis 来源: https://www.cnblogs.com/mollnn/p/14339015.html