• P1514 引水入城


    概述

    首先,这是一道好题,这道题既考查了图论的dfs知识,又考察了区间贪心问题中很典型的区间覆盖问题,着实是一道好题。

    大概思路说明

    我们观察到,只有第一行可以放水库,而第一行在哪里放水库的结果就是直接导致最后一行某些点被覆盖。所以我们只需要找到第一行水库与最后一行被覆盖的关系即可完成决策,中间的行没有意义。我们对于第一行的每一个数进行dfs,可以预处理出所有的区间。然后问题就转化成了用一些区间覆盖一条线段的问题。直接求解即可。

    参考代码

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 505;
    int n, m, high[maxn][maxn], vis[maxn][maxn];
    const int dx[] = {0, 1, 0, -1};
    const int dy[] = {1, 0, -1, 0};
    void dfs(int x, int y) {
    	vis[x][y] = 1;
    	for(int i = 0; i < 4; i++) {
    		int nx = x + dx[i];
    		int ny = y + dy[i];
    		if(nx >= 1 && nx <= m && ny >= 1 && ny <= n &&!vis[nx][ny] && high[nx][ny] < high[x][y]) {
    			dfs(nx, ny);
    		}
    	}
    }
    struct line
    {
    	int left, right, num;
    	bool operator < (const line b) const {
    		if(this->left != b.left) return this->left < b.left;
    		int la = this->right - this->left; 
    		int lb = b.right - b.left;
    		return la > lb;
    	}
    }ls[maxn];
    int main() {
    //	freopen("input.in", "r", stdin);
    	cin >> n >> m;
    	for(int i = 1; i <= n; i++) {
    		for(int j = 1; j <= m; j++) 
    			cin >> high[j][i];
    	}
    	int dfn = 0;
    	for(int i = 1; i <= m; i++) { 
    		memset(vis, 0, sizeof(vis)); 
    		dfs(i, 1);         
    		int l = -1, r = -1; 
    		for(int j = 1; j <= m; j++) {
    			if(vis[j][n]) {l = j; break;}
    		}
    		int j;
    		if(l!=-1)for(j = l; j <= m; j++) {
    			if(!vis[j][n]) {r = j - 1; break;}
    		}
    		if(j == m + 1 && l != -1) r = m;
    		if(l != -1 && r != -1) ls[dfn++] = {l, r, i};
    	} 
    	int s = 1;
    	set<int> ans;
    	set<int> no;
    	while(s <= m) {
    		for(int i = 0; i < dfn; i++) {
    			if(ls[i].left <s ) ls[i].left = s;
    			if(ls[i].left > ls[i].right) ls[i] = {maxn, maxn, maxn};
    		}
    		sort(ls, ls+dfn);
    		if(ls[0].left == maxn) { 						//没有可用的区间 
    			for(int i = s; i <= m; i++) no.insert(i);
    			break;
    		}
    		if(ls[0].left!=s) {
    			for(int i = s; i < ls[0].left; i++) no.insert(i);
    		}
    		ans.insert(ls[0].num);
    		s = ls[0].right+1;
    	}
    	if(no.empty()) {
    		cout << 1 << endl << ans.size();
    	}
    	else {
    		cout << 0 << endl << no.size();
    	}
    	return 0;
    }
    
  • 相关阅读:
    唐骏:学会高明的让员工加班
    [ZT]微软亚洲技术中心面试题[附非標准答案]
    企业的后ERP时代
    WinForm中使用DXperience控件中XtraForm,如何实现换肤
    世卫组织健康食品排行榜:健康肉类减为三种
    [轉載]在研究院的新兵训练
    [转]怎样面对同事升职?
    今天是个好日子!
    程序员跳槽动机被误读,薪资只是表象(图文)
    2008年个人技术十大趋势
  • 原文地址:https://www.cnblogs.com/gengchen/p/6060692.html
Copyright © 2020-2023  润新知