P6517 [CEOI2010 day1] alliances 题解

最大流。


首先,不考虑人类结盟的特殊要求,这道题如何解决?

因为结盟关系只能在相邻两个村庄之间产生,所以把村庄看作结点,结盟关系看作边,那么这将会是一张二分图。

所以可以先将地图黑白染色,将黑点看作源点,白点看作汇点,能够产生结盟关系的结点之间连一条容量为 $1$ 的边,跑一遍最大流即可得到答案。

(注意:在建源点汇点的时候要考虑这个点需要的结盟数量,这一点在多源汇转单源汇的时候就可以处理。)

接着考虑人类的特殊要求:

人类需要恰好两个结盟关系,并且不能同时上下结盟或同时左右结盟。这个要求等价于:在上下结盟关系中选择一个,在左右结盟关系中选择一个

所以,可以对人类的结点拆点,分别拆为:人类的上下结盟关系人类的左右结盟关系,这两个是新的源点(或汇点),并且其容量为 $1$。在连边的时候只连其对应到的结点即可。

剩下的部分和上面说的一样。

这道题的输出也比较麻烦冗长,但是如果理解了建模方式那么也不是难事了。

建模代码(val 表示这个村庄需要的结点数量,id 是拆点过后的点的编号,pxpy 是每个编号对应的位置):

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;
}
posted @ 2024-01-10 17:35  A_box_of_yogurt  阅读(8)  评论(0编辑  收藏  举报  来源
Document