Luogu1514 引水入城
题意比较绕,多看两遍就看懂了
重点在于求满足要求的情况时的答案
可能也是可想的
注意到对于一个第一行的点,如果是满足要求的情况下,
他所能到达的一定是一段连续的区间
考虑如果不连续的话,那一定是绕过了一个区域,
那这一圈都是可以流过去的,而且这一圈都不能流进这个区域
那他就是一个不满足要求的情况
所以对于一个点,他能给供水的是一段区间
那这就转化成了一个线段覆盖问题
正好之前也没做过,这里写一下:
有两种写法,
第一种是贪心:在当前已经选出的区间中找一条左端点在其中,
且右端点最大的线段,之后将这条线段并入已选区间
直至选完
第二种是 dp:f[i] 表示到第 i 个位置最少用 f[i] 条线段覆盖
转移显然是从一段的最小转移,由于要保证最小,
就用线段树维护区间最小就行了
转移的位置只要保证能跟之前的拼起来就行
由于比较懒就写了贪心。。。
需要注意的是贪心的话你要保证跟之前区间接起来的话,是已选区间右端点 + 1就行
代码:
#include <algorithm> #include <iostream> #include <cstring> #include <cstdlib> #include <cctype> #include <cstdio> #include <queue> using namespace std; const int MAXN = 505, MAXM = 505; struct POS{ int x, y; POS(int X = 0, int Y = 0) {x = X; y = Y;} }; struct LINE{ int l, r; LINE(int L = -1, int R = -1) {l = L; r = R;} bool operator < (const LINE& b) const { return ((l == b.l) ? (r > b.r) : (l < b.l)); } inline void update(LINE val) { if (~val.l) { l = ((~l) ? min(l, val.l) : val.l); r = max(r, val.r); } return; } }line[MAXN][MAXM], myb[MAXM]; int n, m, totok; int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1}; int mp[MAXN][MAXM]; bool vis[MAXN][MAXM]; queue<POS> q; inline void chk() { for (int i = 1; i <= m; ++i) { q.push(POS(1, i)); vis[1][i] = true; } while (!q.empty()) { POS cur = q.front(); q.pop(); for (int i = 0; i < 4; ++i) { int tx = cur.x + dx[i], ty = cur.y + dy[i]; if (tx < 1 || tx > n || ty < 1 || ty > m || vis[tx][ty] || mp[cur.x][cur.y] <= mp[tx][ty]) continue; vis[tx][ty] = true; q.push(POS(tx, ty)); } } return; } LINE dfs(POS cur, POS frm) { if (cur.x == n) { line[cur.x][cur.y].update(LINE(cur.y, cur.y)); } for (int i = 0; i < 4; ++i) { int tx = cur.x + dx[i], ty = cur.y + dy[i]; if (tx < 1 || tx > n || ty < 1 || ty > m || (tx == frm.x && ty == frm.y) || mp[cur.x][cur.y] <= mp[tx][ty]) continue; line[cur.x][cur.y].update(dfs(POS(tx, ty), cur)); } return line[cur.x][cur.y]; } inline void getans() { for (int i = 1; i <= m; ++i) myb[i] = line[1][i]; sort(myb + 1, myb + m + 1); LINE curitv; int ans = 1, ptr = 1; while (!(~myb[ptr].l)) ++ptr; curitv = myb[ptr]; ++ptr; while (curitv.r < m) { register int curmax = 0; while (ptr <= m && myb[ptr].l <= curitv.r + 1) { curmax = max(curmax, myb[ptr].r); ++ptr; } curitv.r = curmax; ++ans; } printf("1\n%d\n", ans); return; } int main() { scanf("%d%d", &n, &m); for (int i = 1; i <= n; ++i) for (int j = 1; j <= m; ++j) scanf("%d", &mp[i][j]); chk(); bool GG = false; for (int i = 1; i <= m; ++i) if (!vis[n][i]) { GG = true; ++totok; } if (GG) { printf("0\n%d\n", totok); return 0; } for (int i = 1; i <= m; ++i) dfs(POS(1, i), POS(0, 0)); getans(); return 0; }
禁止诸如开发者知识库/布布扣/码迷/学步园/马开东等 copy 他人博文乃至博客的网站转载
,用户转载请注明出处:https://www.cnblogs.com/xcysblog/