P2472 [SCOI2007]蜥蜴

题目链接

分析

这次来到了一个正儿八经的省选题,紫题难度的,高中那会根本不敢想......

说老实话,如果不是他被放在网络流题单里面,我也不会想到用网络流来做,就离谱

突然发现,这种题目好像有一种共通的性质符合网络流:

  1. 都有一个东西需要从一个地方到另一个地方(即 流量,这题中是蜥蜴)
  2. 每次移动会对所在的地方造成一种损耗,损耗达到一定限度就不再有效(即 边的容量,在这题中是柱子的高度)
  3. 有起点和终点(建立源点和汇点)

既然这样,我们就可以跑一边最大流看看

每个柱子有高度,我们可以使用拆点法拆成两个点,中间所连边的边权为其高度。

柱子和柱子之间暴力连边,好在数据范围很小,并不会T掉。只要柱子高度足够,跳起来并没有啥限制,所以边权设为 INF。

每个柱子看下能不能跳到外面,这里也可以暴力连边,将他们连到汇点,边权设置为 INF。

从源点向每只蜥蜴在的地方连一条边,边权设为 1。(只有一只蜥蜴)

建好图之后,跑一边最大流就完事了。

对了,题目是让求跑不掉的蜥蜴的最小值,所以答案是蜥蜴总数减去最大流的所得值。

代码

#include<bits/stdc++.h>
using namespace std;
const int INF = 1 << 30, N = 1010;
struct Edge {
    int from, to, flow;
    Edge(int u, int v, int f):from(u), to(v), flow(f) {}
};
int n, m, R, s, t;
vector<Edge> edges;
vector<int> G[N];
void addEdge(int from, int to, int flow) {
    edges.push_back((Edge){from, to, flow});
    edges.push_back((Edge){to, from,  0  });
    G[from].push_back(edges.size() - 2);
    G[ to ].push_back(edges.size() - 1);
}
int d[N];
queue<int>q;
bool bfs() {
    memset(d, 0, sizeof(d));
    while (!q.empty()) q.pop();
    q.push(s), d[s] = 1;
    while (!q.empty()) {
        int x = q.front(); q.pop();
        if (x == t) return true;
        for (int i = 0; i < G[x].size(); ++i) {
            Edge &e = edges[G[x][i]];
            int to = e.to;
            if (!d[to] && e.flow)
                q.push(to), d[to] = d[x] + 1;
        }
    }
    return false;
}
int Dinic (int x, int flow) {
    if(x == t) return flow;
    int rest = flow;
    for (int i = 0; i < G[x].size(); ++i) {
        Edge &e = edges[G[x][i]], &fe = edges[G[x][i]^1];
        int to = e.to;
        if (e.flow && d[to] == d[x] + 1) {
            int k = Dinic(to, min(rest, e.flow));
            if (!k) d[to] = 0;
            e.flow -= k, fe.flow += k;
            rest -= k;
            if (rest == 0) break;
        }
    }
    if (flow == rest) d[x] = 0;
    return flow - rest;
}
//
inline int getNum(int x, int y,int id) {
    return 2 * (m*(x-1)+y) - (2-id);
}
inline int dis2(int x, int y, int i, int j) {
    return (x - i) * (x - i) + (y - j) * (y - j);
}
int main()
{
    //input
    scanf("%d%d%d", &n, &m, &R);
    s = 0, t = 2 * n * m + 1;
    char ms[30];
    for (int i = 1; i <= n; ++i){
        scanf("%s", ms + 1);
        for (int j = 1; j <= m; ++j)
            if (ms[j] != '0')
                addEdge(getNum(i, j, 1), getNum(i, j, 2), ms[j] - '0');
    }
    int animals = 0;
    for (int i = 1; i <= n; ++i){
        scanf("%s", ms + 1);
        for (int j = 1; j <= m; ++j)
            if (ms[j] == 'L') {
                ++animals;
                addEdge(s, getNum(i, j, 1), 1);
            }
    }
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j)
            for (int x = 1; x <= n; ++x)
                for (int y = 1; y <= m; ++y)
                    if (dis2(x, y, i, j) <= R * R)
                        addEdge(getNum(i, j, 2), getNum(x, y, 1), INF);
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j) {
            bool flag = false;
            for(int k = 0; k <= m + 1 && !flag; ++k)
                if (dis2(0, k, i, j) <= R * R || dis2(n + 1, k, i, j) <= R * R)
                    addEdge(getNum(i, j, 2), t, INF), flag = true;
            for (int k = 1; k <= n && !flag; ++k)
                if (dis2(k, 0, i, j) <= R * R || dis2(k, m + 1, i, j) <= R * R)
                    addEdge(getNum(i, j, 2), t, INF), flag = true;
        }
	//solve
    int maxflow = 0;
    int flow;
    while (bfs())
        while (flow = Dinic(s, INF)) maxflow += flow;
    //output
	printf("%d\n", animals - maxflow);
	return 0;
}

posted @ 2020-12-22 23:55  cyhforlight  阅读(45)  评论(0编辑  收藏  举报