【NOIP2010】引水入城 {搜索}

时间:2022-12-16 22:58:52

【NOIP2010】引水入城 {搜索}

【NOIP2010】引水入城 {搜索}

【NOIP2010】引水入城 {搜索}

【NOIP2010】引水入城 {搜索}


【题解】这题大体思路就是搜索,方法应该很多。
我的做法是,先从第一行的每一个点出发进行深搜,这样即可判断第n行的点是否能被覆盖。如果不能就输出。
深搜时,还应处理对于第一行每个点在第n行能覆盖的范围,对范围进行排序后贪心地来取即可。
//详见程序


#include <cstdio>
#include <iostream>
#include <algorithm>
const int fx[4][2]={{0,1},{0,-1},{-1,0},{1,0}};
int n,m,ans,anss,k[505],l[505][505],r[505][505],a[505][505];
bool bo[505][505];
    void dfs(int x,int y)
    {
        bo[x][y]=true;
        for (int i=0;i<4;++i) 
        {
            int p=x+fx[i][0],q=y+fx[i][1];
            if (!p || !q || p>n || q>m) continue;
            if (a[p][q]>=a[x][y]) continue;
            if (!bo[p][q]) dfs(p,q);
            l[x][y]=std::min(l[x][y],l[p][q]);
            r[x][y]=std::max(r[x][y],r[p][q]);
        }
    }
    bool comp(int x,int y)
    {
        return l[1][x]<l[1][y] || l[1][x]==l[1][y] && r[1][x]>r[1][y];
    }
int main()
{
    scanf("%d%d\n",&n,&m);
    for (int i=1;i<=n;++i)
        for (int j=1;j<=m;++j) scanf("%d",&a[i][j]);
    for (int i=1;i<n;++i)
        for (int j=1;j<=m;++j) l[i][j]=m+1,r[i][j]=0;
    for (int i=1;i<=m;++i) l[n][i]=r[n][i]=i;
    for (int i=1;i<=m;++i) dfs(1,i);
    int tot=0;
    for (int i=1;i<=m;++i) tot+=(!bo[n][i]);
    if (tot) printf("0\n%d\n",tot);
    else 
    {
        for (int i=1;i<=m;++i) k[i]=i;
        std::sort(k+1,k+m+1,comp);
        int last=1;ans=0;
        for (int i=1;i<=m && last<=m;)
        {
            int mx=0;++ans;
            for (;i<=m && last>=l[1][k[i]];++i)
                mx=std::max(mx,r[1][k[i]]);
            if (last<=mx) last=mx+1;
        }
        printf("1\n%d\n",ans);
    }
    return 0;
}