NOIP2010 引水入城

题意简化

传送门
给定一个矩阵,每个点有高度,矩阵的第一行的每个点都可以修蓄水池,其他点可以修输水站,输水站只能利用高度差来取水,试问最后一行能否都有水
可以则要求最小化蓄水池,不能则求最小化最后一行的干旱点

题解

首先有个很重要的性质,是可以推出来的:
第一行的每个点所能管辖到的最后一行的点一定是连续的
若不是连续的,那么中间断开的点一定不会有其他水源

知道了这个就可以很轻松的搜索出最后一行是否能全部覆盖
然后我们再想想如何把答案最小化
记忆化搜索,嗯

代码

#include<bits/stdc++.h>
#define rnt register int
#define ii inline
#define get getchar();
#define ll long long
using namespace std;
int n,m,a[501][501],r[501],l[501];
bool f[501][501];
ii ll read()
{
    int x=1,k=0;char ch;
    ch=get;while(ch!='-'&&(ch>'9'||ch<'0'))ch=get;
    if(ch=='-')x=-1,ch=get;
    while(ch>='0'&&ch<='9')k=k*10+(ch-'0'),ch=get;;
    return x*k;
}
int xx[4]={0,0,1,-1},yy[4]={1,-1,0,0},q[501];
int ans1=0;bool ans[501];
ii void dfs(rnt x,rnt y,rnt p)
{
    f[x][y]=1;
    if(x==n)
    {
        ans[y]=1;
        r[p]=max(r[p],y);
        l[p]=min(l[p],y);
    }
    for(rnt i=0;i<=3;i++)
    {
        rnt x1=x+xx[i],y1=y+yy[i];
        if(x1>0&&x1<=n&&y1>0&&y1<=m)
        if(a[x1][y1]<a[x][y]&&f[x1][y1]==0)
        {
            dfs(x1,y1,p);
        }
    }
}
int main()
{
    n=read(),m=read();
    for(rnt i=1;i<=m;i++)l[i]=40001,q[i]=40001;
    for(rnt i=1;i<=n;i++)
        for(rnt j=1;j<=m;j++)
            a[i][j]=read();
    for(rnt i=1;i<=m;i++)
    if(a[1][i-1]<=a[1][i]&&a[1][i+1]<=a[1][i]){
        dfs(1,i,i);memset(f,0,sizeof(f));}
    for(rnt i=1;i<=m;i++)
        if(ans[i]==0)ans1++;
    if(ans1)
    {
        cout<<0<<endl<<ans1;
        return 0;
    }
    for(rnt i=1;i<=m;i++)//最后一行
    for(rnt j=1;j<=m;j++)//第一行
    {
        if(i<=r[j]&&i>=l[j])q[i]=min(q[i],q[l[j]-1]+1);
    }
    cout<<1<<endl<<q[m];
}


posted @ 2019-05-03 10:10  yzhx  阅读(212)  评论(0编辑  收藏  举报