zoukankan      html  css  js  c++  java
  • P1514 引水入城

    P1514 引水入城

    给定一张二维高度地图, 你可以在第一行的格子里建水库。 若是两个相邻格子高度差大于 (1), 那么水可以从高的流去低的
    现在问能否使最后一行的每个格子里都有水, 若是能输出 (1) ,再输出最少建水库数; 若是不能输出不能的格子数


    错误日志: 思路错了
    调试日志: 区间覆盖未转换为闭区间


    Solution

    (反思)刚开始想从最后一行倒着搜上去, 用 (bitset) 维护一个01序列表示每个格子至少需要在第一行建哪些水库之一
    过样例交了一发 (40)分。
    然后发现这个东西不是单单取并就好了啊。。处理完之后是个 (k-SAT) 无多项式解的。。

    然后想正解
    有无解很好判断, 搜索一下就出来了, 不可行答案直接统计即可
    讨论有解的情况
    首先对于第一行的每个水库 (x_{i}) , 他能覆盖的最后一行必然是一个连续的区间
    画图很好证明的
    反证法:
    假设存在一种情况使得覆盖情况如下:

    假设蓝色覆盖路线如下:

    因为右边红色被覆盖了, 所以从红色水库到下方必然有一条路径

    发现路径必有交(紫色部分), 所以红色水库的水也会流入蓝色那部分, 假设不成立
    故一座水库能覆盖的最后一行必然是一个连续的区间
    证毕。

    然后搜索一下第一行的每个格子能到达的区间
    做区间最少线段覆盖即可

    Code

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<cstring>
    #include<algorithm>
    #include<climits>
    #define LL long long
    #define REP(i, x, y) for(int i = (x);i <= (y);i++)
    using namespace std;
    int RD(){
        int out = 0,flag = 1;char c = getchar();
        while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}
        while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
        return flag * out;
        }
    const int maxn = 1019;
    int lenx, leny;
    int map[maxn][maxn];
    bool vis[maxn][maxn];
    int l[maxn][maxn], r[maxn][maxn];
    int mx[4] = {0, 0,-1, 1};
    int my[4] = {1,-1, 0, 0};
    bool judge(int x, int y){return !(x < 1 || x > lenx || y < 1 || y > leny);}
    void dfs(int x, int y){
    	vis[x][y] = 1;//记忆化+到达标记
    	REP(k, 0, 3){
    		int nx = x + mx[k], ny = y + my[k];
    		if(!judge(nx, ny) || map[nx][ny] >= map[x][y])continue;
    		if(!vis[nx][ny])dfs(nx, ny);
    		l[x][y] = min(l[x][y], l[nx][ny]);
    		r[x][y] = max(r[x][y], r[nx][ny]);
    		}
    	}
    struct Node{int l, r;}I[maxn];
    int cnt;
    int main(){
    	lenx = RD(), leny = RD();
    	REP(i, 1, lenx)REP(j, 1, leny)map[i][j] = RD();
    	memset(l, 127, sizeof(l));//r初始为0就得
    	REP(i, 1, leny)l[lenx][i] = r[lenx][i] = i;
    	REP(i, 1, leny)dfs(1, i);
    	int flag = 0;
    	REP(i, 1, leny){
    		if(!vis[lenx][i])flag++;
    		if(r[1][i])I[++cnt] = (Node){l[1][i] - 1, r[1][i]};//记录合法线段(记得转换为区间相交)
    		}
    	if(flag){printf("0
    %d
    ", flag);return 0;}
    	int ans = 0, now = 0, next = 0;
    	REP(i, 1, cnt){
    		if(I[i].l <= now)next = max(next, I[i].r);
    		else{
    			ans++, now = next;
    			if(I[i].l > now);//已经判断一定有解了
    			next = max(next, I[i].r);
    			}
    		}
    	puts("1");
    	if(now < leny)printf("%d
    ", ans + 1);
    	else printf("%d
    ", ans);
    	return 0;
    	}
    
  • 相关阅读:
    触发器
    自定义变量
    系统变量
    Interval 计时器
    Ajax 之 DWR
    cssTest
    Ajax之XMLHttpRequst对象
    添加页面元素
    jquery 基础
    jQuery 自定义动画效果
  • 原文地址:https://www.cnblogs.com/Tony-Double-Sky/p/9871976.html
Copyright © 2011-2022 走看看