1 solutions

  • 0
    @ 2025-2-27 14:20:20

    记忆化+区间覆盖

    通过记忆化得到每个点可以覆盖的区间的数目,然后按照区间覆盖进行贪心即可。

    #include<bits/stdc++.h>
    using namespace std;
    typedef pair<int,int> PII;
    #define l first
    #define r second
    const int N=510;
    int n,m;
    int h[N][N];
    PII f[N][N];
    int dx[]={-1,1,0,0},dy[]={0,0,-1,1};
    void dfs(int x,int y)
    {
    	PII& p=f[x][y];
    	if(p.l!=-1) return ; //已经被计算过了
    	p.l=N;//初始化可以覆盖的左边的最小值
    	p.r=0;
    	if(x==n) p={y,y}; //当前点的行列 
    	for(int i=0;i<4;i++)
    	{
    		int a=x+dx[i],b=y+dy[i];
    		if(a>=1&&a<=n&&b>=1&&b<=m&&h[a][b]<h[x][y])
    		{
    			dfs(a,b); //计算周围的点
    			p.l=min(p.l,f[a][b].l); //更新左边值 
    			p.r=max(p.r,f[a][b].r); //更新右边界 
    		}
    	}
    }
    int main()
    {
    	cin>>n>>m;
    	for(int i=1;i<=n;i++)
    	{
    		for(int j=1;j<=m;j++)
    		{
    			cin>>h[i][j];
    		}
    	}
    	memset(f,-1,sizeof f);
    	for(int i=1;i<=m;i++)
    	{
    		dfs(1,i);//计算第一行的每个元素可以覆盖的区间 
    	}
    	int cnt=0;
    	for(int i=1;i<=m;i++)
    	{
    		if(f[n][i].l==-1)
    		{
    			cnt++;
    		}
    	}
    	if(cnt)
    	{
    		cout<<0<<endl<<cnt<<endl;
    	}
    	else
    	{
    		vector<PII> segs;
    		for(int i=1;i<=m;i++)
    		{
    			segs.push_back({f[1][i]});
    		}
    		sort(segs.begin(),segs.end());//按照区间左端点排序 
    		int res=0;
    		for(int i=0,start=1;i<m;)
    		{
    			int maxr=0;
    			while(i<m&&segs[i].l<=start) //还在当前区间内 
    			//选择当前这个区间可以走到的最远的地方 
    			{
    				maxr=max(maxr,segs[i].r);
    				i++;
    			}
    			res++; //选择当前这个区间 
    			if(maxr>=m) break; //已经覆盖完成 
    			start=maxr+1; //从下一个点开始覆盖 
    		}
    		cout<<1<<endl<<res<<endl;
    	}
    	return 0;
    }
    
    • 1

    Information

    ID
    1087
    Time
    1000ms
    Memory
    256MiB
    Difficulty
    10
    Tags
    # Submissions
    1
    Accepted
    1
    Uploaded By