洛谷P1514-引水入城(dfs+贪心区间覆盖)

传送门

首先通过佬的博客可以得到一个结论:当最后有解时,每个蓄水厂在最后一行能够覆盖到的区间一定是连续的,由此可以将其转化为区间覆盖问题进行贪心。
在这里插入图片描述

考虑用 p a i r pair pair 存储对于第一行的第 i i i 个点,其在最后一行能覆盖到的区间的左端点和右端点。由于最后需要贪心选择最小的区间以覆盖整个 [ 1 , m ] [1,m] [1,m] 范围,因此在每次的 d f s dfs dfs 之前都要把 v i s vis vis 数组进行清空,防止第 i i i 点的左端点答案受第 i − 1 i-1 i1 点的右端点答案影响。而考虑到 v i s vis vis 数组的清空问题,可以在求有解答案之前,先跑一遍判断是否无解。

n = = 1 n==1 n==1 时将跑出死循环,因此需要进行特判。同时进行了一个优化操作:仅有第 i i i 个点能够流到第 2 2 2 行的对应点时,才会对其进行 d f s dfs dfs(其实也可以直接跑某个第一行的点是否能被之前已访问过的点覆盖,若覆盖则不用对该点进行 d f s dfs dfs ,因为该点能够产生的所有贡献都已经包含在前一个点的答案内)。

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=510;
int n,m,now;
int g[N][N],vis[N][N];
pair<int,int> pos[N];

void dfs(int x,int y,int st){
    vis[x][y]=1;
    if(x==n-1&&st){
		pos[now].first=min(pos[now].first,y);
		pos[now].second=max(pos[now].second,y);
	}
    if (x>=1&&!vis[x-1][y]&&g[x][y]>g[x-1][y])
		dfs(x-1,y,st);
    if (x<n-1&&!vis[x+1][y]&&g[x][y]>g[x+1][y])
		dfs(x+1,y,st);
    if (y>=1&&!vis[x][y-1]&&g[x][y]>g[x][y-1])
		dfs(x,y-1,st);
    if (y<m-1&&!vis[x][y+1]&&g[x][y]>g[x][y+1])
		dfs(x,y+1,st);
}

signed main(){
    cin>>n>>m;
    for(int i=0;i<n;i++)
    	for(int j=0;j<m;j++)
    		cin>>g[i][j];
    
    //对于没有答案时的处理 
	for(int i=0;i<m;i++)
    	dfs(0,i,0);
	int ans=0;
	for(int i=0;i<m;i++)
    	if (!vis[n-1][i])
			ans++;	
    if(ans){
		cout<<0<<endl<<ans;
		return 0;
	}
    
	for(int i=0;i<m;i++){
        memset(vis,0,sizeof(vis));
        now=i;
		pos[now].first=501;
        if(n==1)//特判只有一行的情况时 
			dfs(0,i,1);
        else if(g[0][i]>g[1][i])
			dfs(1,i,1);
    }
    
    int maxx;
    now=-1;
    while(now<m-1){//选择最少区间覆盖整个区间的贪心问题 
        maxx=-1;
        for(int i=0;i<m;i++)
        	if(pos[i].first<=now+1&&pos[i].second>maxx)
				maxx=pos[i].second;
        ans++;
		now=maxx;
    }
    cout<<1<<endl<<ans;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值