zoukankan      html  css  js  c++  java
  • 「NOIP2010」引水入城

    传送门
    Luogu

    解题思路

    第一问很好做,只要总第一行的每一个点都跑一边dfs,判断最后一行是否有点标记不了即可。
    考虑处理第二问。
    其实这一问就是:
    把第一行的点都看做是对最后一行一些点的覆盖,求最后一行那段区间的最小覆盖数。
    我们可以发现这样一个事情:
    每一个第一行的点在最后一行覆盖的都是一段连续的区间。

    证明:
    假设一个点它的水流只可以覆盖两个最后一行的两端不相邻区间(多段类似)。
    那么在有解的前提下,必定会有一条水流流入中间那块没被覆盖的区域,
    而这条水流一定会与第一条水流相交,这就意味着第一条水流可以在交点处分一条支流 从而覆盖整个区间,与假设矛盾。

    所以我们可以在dfs时预处理出每个第一行节点对应的区间,然后贪心地去选点就好了。

    细节注意事项

    • 第一次没用上vis标记居然还只T了两个点hhh

    参考代码

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdlib>
    #include <cstdio>
    #include <cctype>
    #include <cmath>
    #include <ctime>
    #define rg register
    using namespace std;
    template < typename T > inline void read(T& s) {
    	s = 0; int f = 0; char c = getchar();
    	while (!isdigit(c)) f |= c == '-', c = getchar();
    	while (isdigit(c)) s = s * 10 + (c ^ 48), c = getchar();
    	s = f ? -s : s;
    }
    
    const int _ = 502;
    const int dx[] = { 1, -1, 0, 0 };
    const int dy[] = { 0, 0, 1, -1 };
    
    int n, m, d[_][_];
    int vis[_][_], l[_][_], r[_][_];
    
    inline void dfs(int i, int j) {
    	if (vis[i][j]) return; vis[i][j] = 1;
    	for (rg int k = 0; k < 4; ++k) {
    		int ni = i + dx[k], nj = j + dy[k];
    		if (ni < 1 || ni > n || nj < 1 || nj > m) continue;
    		if (d[ni][nj] >= d[i][j]) continue;
    		dfs(ni, nj);
    		l[i][j] = min(l[i][j], l[ni][nj]);
    		r[i][j] = max(r[i][j], r[ni][nj]);
    	}
    }
    
    int main() {
    #ifndef ONLINE_JUDGE
    	freopen("in.in", "r", stdin);
    #endif
    	read(n), read(m);
    	for (rg int i = 1; i <= n; ++i)
    		for (rg int j = 1; j <= m; ++j)
    			read(d[i][j]);
    	memset(l, 0x3f, sizeof l);
    	memset(r, 0, sizeof r);
    	for (rg int j = 1; j <= m; ++j)
    		l[n][j] = r[n][j] = j;
    	for (rg int j = 1; j <= m; ++j)
    		if (!vis[1][j]) dfs(1, j);
    	int cnt = 0;
    	for (rg int j = 1; j <= m; ++j)
    		cnt += !vis[n][j];
    	if (cnt) { printf("0
    %d
    ", cnt); return 0; }
    	int ans = 0;
    	for (rg int R, L = 1; L <= m; L = R + 1) {
    		R = 0;
    		for (rg int j = 1; j <= m; ++j)
    			if (l[1][j] <= L) R = max(R, r[1][j]);
    		++ans;
    	}
    	printf("1
    %d
    ", ans);
    	return 0;
    }
    

    完结撒花 (qwq)

  • 相关阅读:
    谈谈Nginx有哪些特点
    网站嵌入百度地图制作
    8张图理解Java
    linux问题-easy_install安装bpython时报错
    linux问题-Centos 安装Sublime text 3
    python例子-Nmap扫描IP并更新
    python例子-PyQuery抓取信息.
    python例子-MySQLdb和练习题
    python例子-线程和队列
    mysql问题-centos7中mysql远程连接问题
  • 原文地址:https://www.cnblogs.com/zsbzsb/p/11755832.html
Copyright © 2011-2022 走看看