[题解] luogu P1514 引水入城 DFS + 贪心覆盖区间

原题链
打了一上午,我真是弱爆了

看完题目,可以很显然的想到一种搜法:
DFS/BFS第1个到第m个临湖城市,求出干旱区城市能否全有水,很显然,这样时间会炸

  • 此时,我们可以在选择搜第i个临海城市加一个剪枝:
if (c[1][i-1] < c[1][i] && c[1][i+1] < c[1][i])
    dfs();

意思说,当且仅当 i 的前一个临湖城市和后一个临海城市的海拔都小于当前临湖城市海拔,我才去搜这个城市
为什么?
你会发现,一个临湖城市要是比自己相邻的临湖城市海拔小,就可以通过相邻的城市个自己输水,那么自己再建个蓄水站就没有必要了

当我们完成了搜索,就已经做完了第一种情况,也就是干旱区城市不能全建输水站的情况,记录下输出即可

此时,我们要求的是最少建几个蓄水站,那么可以贪心:

  • 可以发现,现在既然每个干旱区城市都可以建到输水站,那么第 i 个临海城市所可以扩展出来的干旱城市是一段连续的区间
  • 我们这样想:在前面dfs的时候,记录第 i 个临湖城市可以扩展出来的干旱区城市区间的左端点和右端点,这样问题就转换成了:给定一个长度为m的区间,再给出n条线段的起点和终点,求最少使用多少条线段可以将整个区间完全覆盖
  • 这就是贪心区间覆盖,我们可以通过以下步骤求解,好好理解(巨佬自行屏蔽):
  1. 将所有线段从小到大排序,先比较左端点,一样的话就比较右端点
  2. 每次在线段中找出所有左端点小于等于当前已覆盖到的区间右端点的线段,选择右端点最大并且大于当前已覆盖到的区间右端点,重复以上操作直至覆盖整个区间

其正确性就不再证明

然后这道题就做完了:

#include <bits/stdc++.h>
using namespace std;

int n, m, c[550][550], _desert[550];
int L, R, now, ans, maxr, maxnum, vis[550][550];
int move1[5] = {0, 1, 0, -1, 0};
int move2[5] = {0, 0, 1, 0, -1};

struct Range {
    int l, r;
}_sea[550];
int vcmp(Range a, Range b) {
    if (a.l < b.l) return a.l > b.l;
    if (a.l > b.l) return a.l < b.l;
    return a.r < b.r;
}
inline void GREEDY() {
    sort(_sea + 1, _sea + m + 1, vcmp);
    for (int i = 1; i <= m; ++i)
        if (_sea[i].l == 1)
            R = max(R, _sea[i].r);
    maxr = R;
    ++ans;
    while (R < m) {
        maxr = 0;
        for (int i = 1; i <= m; ++i)
            if (_sea[i].l <= R + 1 && _sea[i].r > maxr)
                maxr = _sea[i].r;
        R = maxr;
        ++ans;
    }
    printf ("1\n%d\n", ans);
}
void dfs_answer(int x, int y) {
    vis[x][y] = 1;
    if (x == n) {
        _desert[y] = 1;
        _sea[now].l = min(_sea[now].l, y);
        _sea[now].r = max(_sea[now].r, y);
    } int xi, yi;
    for (int i = 1; i <= 4; ++i) {
        xi = x + move1[i];
        yi = y + move2[i];
        if (xi > 0 && xi <= n && yi > 0 && yi <= m)
            if (c[xi][yi] < c[x][y] && vis[xi][yi] == 0)
                dfs_answer(xi, yi);
    }
}
int main() {
    scanf ("%d%d", &n, &m);
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j)
            scanf ("%d", &c[i][j]);
    for (int i = 1; i <= m; ++i) {
        _sea[i].l =
        _sea[i].l = m + 1;
        _sea[i].r = 0;
        if (c[1][i - 1] > c[1][i] || c[1][i + 1] > c[1][i])
            continue;
        now = i;
        dfs_answer(1, i);
        memset(vis, 0, sizeof(vis));
    }
    for (int i = 1; i <= m; ++i)
        if (_desert[i] == 0) ++ans;
    if (ans != 0) {
        printf ("0\n%d\n", ans);
        return 0;
    }
    GREEDY();
    return 0;
}

原文地址:https://www.cnblogs.com/martixx/p/11232431.html

时间: 2024-08-02 16:58:51

[题解] luogu P1514 引水入城 DFS + 贪心覆盖区间的相关文章

Luogu P1514 引水入城

题目描述 在一个遥远的国度,一侧是风景秀美的湖泊,另一侧则是漫无边际的沙漠.该国的行政区划十分特殊,刚好构成一个 \(N\) 行 \(\times M\) 列的矩形,如上图所示,其中每个格子都代表一座城市,每座城市都有一个海拔高度. 为了使居民们都尽可能饮用到清澈的湖水,现在要在某些城市建造水利设施.水利设施有两种,分别为蓄水厂和输水站.蓄水厂的功能是利用水泵将湖泊中的水抽取到所在城市的蓄水池中. 因此,只有与湖泊毗邻的第\(1\)行的城市可以建造蓄水厂.而输水站的功能则是通过输水管线利用高度落

P1514 引水入城 DFS

题目描述 在一个遥远的国度,一侧是风景秀美的湖泊,另一侧则是漫无边际的沙漠.该国的行政区划十分特殊,刚好构成一个NN 行\times M×M 列的矩形,如上图所示,其中每个格子都代表一座城市,每座城市都有一个海拔高度. 为了使居民们都尽可能饮用到清澈的湖水,现在要在某些城市建造水利设施.水利设施有两种,分别为蓄水厂和输水站.蓄水厂的功能是利用水泵将湖泊中的水抽取到所在城市的蓄水池中. 因此,只有与湖泊毗邻的第11 行的城市可以建造蓄水厂.而输水站的功能则是通过输水管线利用高度落差,将湖水从高处向

luogu 1066 引水入城(bfs+贪心)

90分,有一个点TLE.... 首先可以证明一个东西,如果从上面一排的某个点bfs一次到最下面一排的饮水点不是一个区间的话,那么最后一定所有饮水点不会被覆盖完的. 证明考虑反证法. 所以从上面一排的每个点bfs一次得到一个区间.题目转化为给出m个区间覆盖m个点的最小区间选择数. 显然是个明显的贪心,以左区间端点为第一关键字升序排序,右区间端点为第二关键字降序排序,那么每次贪心的选择一个覆盖最大的区间即可. 时间复杂度O(n*m^2+mlogm).需要常数优化. # include <cstdio

洛谷 P1514 引水入城

P1514 引水入城 题目描述 在一个遥远的国度,一侧是风景秀美的湖泊,另一侧则是漫无边际的沙漠.该国的行政区划十分特殊,刚好构成一个N 行M 列的矩形,如上图所示,其中每个格子都代表一座城市,每座城市都有一个海拔高度. 为了使居民们都尽可能饮用到清澈的湖水,现在要在某些城市建造水利设施.水利设施有两种,分别为蓄水厂和输水站.蓄水厂的功能是利用水泵将湖泊中的水抽取到所在城市的蓄水池中. 因此,只有与湖泊毗邻的第1 行的城市可以建造蓄水厂.而输水站的功能则是通过输水管线利用高度落差,将湖水从高处向

CODEVS 1066/洛谷 P1514引水入城

1066 引水入城 2010年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description 在一个遥远的国度,一侧是风景秀美的湖泊,另一侧则是漫无边际的沙漠.该国的行政 区划十分特殊,刚好构成一个N行M列的矩形,如上图所示,其中每个格子都代表一座城 市,每座城市都有一个海拔高度. 为了使居民们都尽可能饮用到清澈的湖水,现在要在某些城市建造水利设施.水利设施 有两种,分别为蓄水厂和输水站.蓄水厂的功能是利用水泵将湖

P1514 引水入城

#include<iostream> #include<cstring> #include<algorithm> using namespace std; struct def1 { int x; int y; } q[3000000]; struct def2 { int len; int x; int y; } val[550]; int dctx[6]= {0,1,0,-1,0},dcty[6]= {0,0,1,0,-1}; int n,m,h=0,t=0,cnt

[洛谷P1514]引水入城

题目大意:有一个n*m的矩阵,每个格子一个高度,第一行可以放蓄水站,可以向四周比这格高度小的格子送水.问可不可以让第n行都有水,若可以输出最少建几个蓄水站,否则输出最少有几个格子没有水 题解:对于每个格子处理出它可以到的最左端和最右段,因为如果有解,可覆盖的区间连续,所以记忆化搜索.最后线段覆盖就好了. 卡点:dfs中的变量设成了全局变量,然后出锅 C++ Code: #include<cstdio> #include<cctype> #include<cstring>

P1514 引水入城[搜索,线段覆盖]

题目描述 在一个遥远的国度,一侧是风景秀美的湖泊,另一侧则是漫无边际的沙漠.该国的行政区划十分特殊,刚好构成一个\(N\) 行\(M\) 列的矩形,如上图所示,其中每个格子都代表一座城市,每座城市都有一个海拔高度. 为了使居民们都尽可能饮用到清澈的湖水,现在要在某些城市建造水利设施.水利设施有两种,分别为蓄水厂和输水站.蓄水厂的功能是利用水泵将湖泊中的水抽取到所在城市的蓄水池中. 因此,只有与湖泊毗邻的第1行的城市可以建造蓄水厂.而输水站的功能则是通过输水管线利用高度落差,将湖水从高处向低处输送

P1514 引水入城 [记忆化搜索]

题目描述 在一个遥远的国度,一侧是风景秀美的湖泊,另一侧则是漫无边际的沙漠.该国的行政区划十分特殊,刚好构成一个NN 行\times M×M 列的矩形,如上图所示,其中每个格子都代表一座城市,每座城市都有一个海拔高度. 为了使居民们都尽可能饮用到清澈的湖水,现在要在某些城市建造水利设施.水利设施有两种,分别为蓄水厂和输水站.蓄水厂的功能是利用水泵将湖泊中的水抽取到所在城市的蓄水池中. 因此,只有与湖泊毗邻的第11 行的城市可以建造蓄水厂.而输水站的功能则是通过输水管线利用高度落差,将湖水从高处向