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

    题目传送门

    dfs+性质题,最直接的想法,求出第一行的每个点可以覆盖最后一行哪些点,然后做处理.

    但是我们求出来的有可能有一些是不连续的区间,怎么办?(想了好久),其实要用到本题的一个性质,如果最后一行的某个点的左右两个点都被第一行的同一个点覆盖而这个点没有被覆盖,那就说明第一行输出是0,简单求出不能被覆盖的点数就行.

    剩下的情况就是区间覆盖问题了,要注意更新边界的细节(调了好久).

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    
    using namespace std;
    
    int n,m,a[501][501],tot,ans;
    bool vis[501][501],fla[501],k[501][501],vv[501][501];
    int xx[] = {-1,0,1,0};
    int yy[] = {0,-1,0,1};
    struct kkk {
    	int x,y,z,vis,l,r;
    }e[501],sum[501];
    
    inline bool cmp(kkk s,kkk d) {
    	if(s.z == d.z) return s.y < d.y;
    	return s.z > d.z;
    }
    
    inline void dfs(int x,int y,int id) {
    	int x1,y1;
    	for(int i = 0;i <= 3; i++) {
    		x1 = x + xx[i];
    		y1 = y + yy[i];
    		if(x1 > n || x1 <= 0 || y1 > m || y1 <= 0) continue;
    		if(a[x1][y1] >= a[x][y]) continue;
    		if(vis[x1][y1]) continue;
    		vis[x1][y1] = 1;
    		vv[x1][y1] = 1;
    		if(x1 == n) {
    			e[id].l = min(e[id].l,y1);
    			e[id].r = max(e[id].r,y1);
    			k[id][y1] = 1;
    		}
    		dfs(x1,y1,id);
    	}
    }
    
    inline bool dp(kkk s,kkk d) {
    	return s.l < d.l;
    }
    
    int main() {
    	scanf("%d%d",&n,&m);
    	for(int i = 1;i <= n; i++)
    		for(int j = 1;j <= m; j++) {
    			scanf("%d",&a[i][j]);
    			if(1 == i) {
    				e[j].l = 600;
    				if(n == 1) e[j].l = j,e[j].r = j;
    				e[j].x = i;
    				e[j].y = j;
    				e[j].z = a[i][j];
    				e[j].vis = 1;
    			}
    		}
    	sort(e+1,e+m+1,cmp);
    	for(int i = 1;i <= m; i++) {
    		if(fla[e[i].y]) continue;
    		fla[e[i].y] = 1;
    		vv[e[i].x][e[i].y] = 1;
    		memset(vis,0,sizeof(vis));
    		dfs(e[i].x,e[i].y,i);
    		for(int j = e[i].y - 1;j >= 1; j--) {
    			if(a[1][j] >= a[1][j+1]) break;
    			fla[j] = 1;
    		}
    		for(int j = e[i].y + 1;j <= m; j++) {
    			if(a[1][j] >= a[1][j-1]) break;
    			fla[j] = 1;
    		}
    		sum[++tot] = e[i];
    	}
    	for(int i = 1;i <= m; i++)
    		if(!vv[n][i])
    			ans++;
    	if(ans != 0) {
    		printf("0
    %d",ans);
    		return 0;
    	}
    	sort(sum+1,sum+1+tot,dp);
    	int R = 1,p = 1,rr = 0,ans;
    	for(p;p <= tot; p++) {
    		if(R > m) break;
    		if(sum[p].l > R) {
    			ans++;
    			R = rr + 1;//如果两个区间是[1,2][3,4]那这两个区间的并也合法 
    		}
    		rr = max(rr,sum[p].r);
    	}
    	printf("1
    ");
    	if(R <= m) ans++;//因为R=rr+1,所以R==m时实际上并没有取到m 
    	printf("%d",ans);
    	return 0;
    } 
    
  • 相关阅读:
    (转)JQuery中$.ajax()方法参数详解
    __dopostback的用法 . 编辑
    (转)__dopostback的用法 .
    (转)如何区分一个程序员是“老手“还是“新手“?
    jQuery验证框架 .
    location.href的用法
    为用户设置密码
    设置环境变量
    用 xampp 在ubuntu 下配置php 运行环境 lampp
    安装与配置JDK
  • 原文地址:https://www.cnblogs.com/lipeiyi520/p/13832523.html
Copyright © 2011-2022 走看看