P6517 [CEOI2010 day1] alliances 题解
最大流。
首先,不考虑人类结盟的特殊要求,这道题如何解决?
因为结盟关系只能在相邻两个村庄之间产生,所以把村庄看作结点,结盟关系看作边,那么这将会是一张二分图。
所以可以先将地图黑白染色,将黑点看作源点,白点看作汇点,能够产生结盟关系的结点之间连一条容量为 $1$ 的边,跑一遍最大流即可得到答案。
(注意:在建源点汇点的时候要考虑这个点需要的结盟数量,这一点在多源汇转单源汇的时候就可以处理。)
接着考虑人类的特殊要求:
人类需要恰好两个结盟关系,并且不能同时上下结盟或同时左右结盟。这个要求等价于:在上下结盟关系中选择一个,在左右结盟关系中选择一个。
所以,可以对人类的结点拆点,分别拆为:人类的上下结盟关系和人类的左右结盟关系,这两个是新的源点(或汇点),并且其容量为 $1$。在连边的时候只连其对应到的结点即可。
剩下的部分和上面说的一样。
这道题的输出也比较麻烦冗长,但是如果理解了建模方式那么也不是难事了。
建模代码(val
表示这个村庄需要的结点数量,id
是拆点过后的点的编号,px
和 py
是每个编号对应的位置):
void add(int fx, int fy, int tx, int ty) {
int f = id[fx][fy][0], t = id[tx][ty][0];
if(val[fx][fy] == 2) {
if(fx == tx) f = id[fx][fy][1];
else f = id[fx][fy][2];
}
if(val[tx][ty] == 2) {
if(fx == tx) t = id[tx][ty][1];
else t = id[tx][ty][2];
}
add_edge(f, t, 1);
}
//下面是 main 函数里面的部分
for(int i = 1; i <= r; ++i) {
for(int j = 1; j <= c; ++j) {
cin >> val[i][j];
sum += val[i][j];
if(val[i][j]) {
id[i][j][0] = ++cnt;
px[id[i][j][0]] = i, py[id[i][j][0]] = j;
if(val[i][j] == 2) {
id[i][j][1] = ++cnt, id[i][j][2] = ++cnt;
px[id[i][j][1]] = px[id[i][j][2]] = i;
py[id[i][j][1]] = py[id[i][j][2]] = j;
}
}
}
}
if(sum & 1) {
cout << "Impossible!";
return 0;
}
for(int i = 1; i <= r; ++i) {
for(int j = 1; j <= c; ++j) {
if(val[i][j]) {
if((i + j) & 1) {
add_edge(s, id[i][j][0], val[i][j]);
if(val[i][j] == 2) {
add_edge(id[i][j][0], id[i][j][1], 1);
add_edge(id[i][j][0], id[i][j][2], 1);
}
for(int k = 0; k < 4; ++k) {
x = i + dx[k], y = j + dy[k];
if(x >= 1 && x <= r && y >= 1 && y <= c && val[x][y]) {
add(i, j, x, y);
}
}
}
else {
add_edge(id[i][j][0], t, val[i][j]);
if(val[i][j] == 2) {
add_edge(id[i][j][1], id[i][j][0], 1);
add_edge(id[i][j][2], id[i][j][0], 1);
}
}
}
}
}
完整代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
using flow_type = ll;
constexpr int inf = 1 << 30;
int St, Ed;
struct edge {
int to;
flow_type c;
int pos;
edge(int To = 0, flow_type C = 0, int Pos = 0): to(To), c(C), pos(Pos) {}
};
vector<edge> g[15005];
void add_edge(int from, int to, flow_type c, bool directed = true) {
// cerr << "from " << from << " to " << to << " with " << c << '\n';
if(!c) return;
g[from].push_back(edge(to, c));
g[to].push_back(edge(from, directed ? 0 : c));
g[from].back().pos = g[to].size() - 1;
g[to].back().pos = g[from].size() - 1;
}
namespace Dinic {
int dep[15005], cur[15005];
queue<int> q;
bool bfs(int s, int t) {
fill(dep + St, dep + 1 + Ed, 0);
dep[s] = 1;
q.push(s);
int now;
while(!q.empty()) {
now = q.front();
q.pop();
for(const auto& i : g[now]) {
if(!dep[i.to] && i.c) {
dep[i.to] = dep[now] + 1;
q.push(i.to);
}
}
}
return dep[t];
}
flow_type dfs(int now, flow_type flw, const int& t) {
if(now == t) return flw;
flow_type rest = flw, f;
const int len = (int)g[now].size();
while(cur[now] < len) {
auto& i = g[now][cur[now]];
if(dep[i.to] == dep[now] + 1 && i.c) {
f = dfs(i.to, min(i.c, rest), t);
if(!f) dep[i.to] = 0;
i.c -= f;
g[i.to][i.pos].c += f;
rest -= f;
if(!rest) break;
}
++cur[now];
}
return flw - rest;
}
flow_type Dinic(int s, int t) {
flow_type flow = 0;
while(bfs(s, t)) {
fill(cur + St, cur + 1 + Ed, 0);
flow += dfs(s, inf, t);
}
return flow;
}
}
constexpr int dx[] = {-1, 0, 1, 0};
constexpr int dy[] = {0, -1, 0, 1};
int r, c, s, t, cnt, sum, x, y, px[15005], py[15005], val[75][75], id[75][75][3];
char put[220][220];
vector<edge> v;
void add(int fx, int fy, int tx, int ty) {
int f = id[fx][fy][0], t = id[tx][ty][0];
if(val[fx][fy] == 2) {
if(fx == tx) f = id[fx][fy][1];
else f = id[fx][fy][2];
}
if(val[tx][ty] == 2) {
if(fx == tx) t = id[tx][ty][1];
else t = id[tx][ty][2];
}
add_edge(f, t, 1);
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> r >> c;
s = ++cnt, t = ++cnt;
for(int i = 1; i <= r; ++i) {
for(int j = 1; j <= c; ++j) {
cin >> val[i][j];
sum += val[i][j];
if(val[i][j]) {
id[i][j][0] = ++cnt;
px[id[i][j][0]] = i, py[id[i][j][0]] = j;
if(val[i][j] == 2) {
id[i][j][1] = ++cnt, id[i][j][2] = ++cnt;
px[id[i][j][1]] = px[id[i][j][2]] = i;
py[id[i][j][1]] = py[id[i][j][2]] = j;
}
}
}
}
if(sum & 1) {
cout << "Impossible!";
return 0;
}
for(int i = 1; i <= r; ++i) {
for(int j = 1; j <= c; ++j) {
if(val[i][j]) {
if((i + j) & 1) {
add_edge(s, id[i][j][0], val[i][j]);
if(val[i][j] == 2) {
add_edge(id[i][j][0], id[i][j][1], 1);
add_edge(id[i][j][0], id[i][j][2], 1);
}
for(int k = 0; k < 4; ++k) {
x = i + dx[k], y = j + dy[k];
if(x >= 1 && x <= r && y >= 1 && y <= c && val[x][y]) {
add(i, j, x, y);
}
}
}
else {
add_edge(id[i][j][0], t, val[i][j]);
if(val[i][j] == 2) {
add_edge(id[i][j][1], id[i][j][0], 1);
add_edge(id[i][j][2], id[i][j][0], 1);
}
}
}
}
}
St = 1, Ed = cnt;
if(Dinic::Dinic(s, t) != (sum >> 1)) {
cout << "Impossible!";
return 0;
}
else {
memset(put, '.', sizeof(put));
for(int i = 1; i <= r; ++i) {
for(int j = 1; j <= c; ++j) {
if(val[i][j]) {
put[(i - 1) * 3 + 2][(j - 1) * 3 + 2] = 'O';
if((i + j) & 1) {
v.clear();
if(val[i][j] == 2) {
for(const auto& k : g[id[i][j][1]]) v.push_back(k);
for(const auto& k : g[id[i][j][2]]) v.push_back(k);
}
else for(const auto& k : g[id[i][j][0]]) v.push_back(k);
for(const auto& k : v) {
if(!k.c) {
x = px[k.to], y = py[k.to];
if(x == i + 1) put[(i - 1) * 3 + 3][(j - 1) * 3 + 2] = put[(x - 1) * 3 + 1][(y - 1) * 3 + 2] = 'X';
if(x == i - 1) put[(i - 1) * 3 + 1][(j - 1) * 3 + 2] = put[(x - 1) * 3 + 3][(y - 1) * 3 + 2] = 'X';
if(y == j + 1) put[(i - 1) * 3 + 2][(j - 1) * 3 + 3] = put[(x - 1) * 3 + 2][(y - 1) * 3 + 1] = 'X';
if(y == j - 1) put[(i - 1) * 3 + 2][(j - 1) * 3 + 1] = put[(x - 1) * 3 + 2][(y - 1) * 3 + 3] = 'X';
}
}
}
}
}
}
for(int i = 1; i <= r * 3; ++i) {
for(int j = 1; j <= c * 3; ++j) {
cout << put[i][j];
}
cout << '\n';
}
}
return 0;
}
本文来自博客园,作者:A_box_of_yogurt,转载请注明原文链接:https://www.cnblogs.com/A-box-of-yogurt/p/18016393