zoukankan      html  css  js  c++  java
  • 洛谷 P1514 引水入城 题解

    这道题经常是作为一个搜索题出现的,但是实际上它还用dp或贪心处理搜索后的结果。

    来看这道题,题意很好理解,第一问也很好做(从每个第一行的点开始搜,判断整个第一行在第N行上覆盖的点数量是否等于M就好了)

    然而,想到这里还不足以解决第二问。

    想要解决第二问首先需要明确一个引理:第一行某个点在第N行上覆盖的点一定是一个区间(这个自己推或看洛谷题解里的证明,实际并不是很难想)

    到了这里,问题就转化为了用最少的子区间覆盖全区间的问题。

    这个问题有两种方法:dp和贪心,这里我选择的是贪心。

    贪心策略:对于全区间的某个点,包含该点且右端点尽量大的子区间是合法且最优的。

    注:洛谷上需要一个小优化:如果第一行上的某个点x可以从其他第一行上的点y到达,那么不需要对x点进行搜索(因为路径x集合真包含于路径y集合),代码中mark数组就是完成这个优化的。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define int long long
    #define maxn 510
    #define rep(i,s,e) for(register int i=s;i<=e;++i)
    #define dwn(i,s,e) for(register int i=s;i>=e;--i)
    using namespace std;
    inline int read()
    {
        int x=0,f=1;
        char c=getchar();
        while(c<'0'||c>'9') {if(c=='-') f=-1; c=getchar();}
        while(c>='0'&&c<='9') {x=x*10+c-'0'; c=getchar();}
        return f*x;
    }
    inline void write(int x)
    {
        if(x<0){putchar('-');x=-x;}
        if(x>9)write(x/10);
        putchar(x%10+'0');
    }
    int n,m; 
    int map[maxn][maxn];
    int book[maxn][maxn];
    int mark[maxn];
    int last_row[maxn];
    struct node
    {
        int l,r;
    }s[maxn];
    int dx[5]={0,1,-1,0,0};
    int dy[5]={0,0,0,1,-1};
    bool cmp(node x,node y)
    {
        return x.r>y.r;
    }
    void dfs(int x,int y)
    {
        if(x==n) last_row[y]++;
        if(x==1) mark[y]=1;
        book[x][y]=1;
        rep(i,1,4)
        {
            int xx=x+dx[i],yy=y+dy[i];
            if(xx>=1&&xx<=n&&yy>=1&&yy<=m&&map[xx][yy]<map[x][y]&&book[xx][yy]==0) 
                dfs(xx,yy);
        }
    }
    signed main()
    {
        n=read();m=read();
        rep(i,1,n)
            rep(j,1,m)
                map[i][j]=read();
        rep(i,1,m)
        {
            if(mark[i]==1) continue;
            memset(book,0,sizeof(book));
            dfs(1,i);
            rep(j,1,m)
            {
                if((book[n][j]!=0&&book[n][j-1]==0)||(book[n][j]!=0&&j==1)) s[i].l=j;
                if(book[n][j]==0&&book[n][j-1]!=0) s[i].r=j-1;
                else if(j==m&&book[n][j]!=0) s[i].r=j;
            }
        }
        int cnt=0;
        rep(i,1,m) 
        {
            if(last_row[i]!=0) ++cnt;
        }
        if(cnt==m) 
        {
            cout<<1<<endl;
            sort(s+1,s+m+1,cmp); 
            int ans=0;
            rep(i,1,m)
                rep(j,1,m)
                    if(i>=s[j].l&&i<=s[j].r) 
                    {
                        i=s[j].r;
                        ++ans;
                        break;
                    }
            cout<<ans;
        }
        else 
        {
            cout<<0<<endl<<m-cnt;
            return 0;
        }
        return 0;
    }
  • 相关阅读:
    String_字符串各个场景下的==
    jvm_run-time method area
    jvm类加载_类的流程
    TypeError: Restaurant() takes no arguments
    EMC测试国家标准GB/T 17626
    8-8 用户的专辑
    8-7 专辑
    8-6 城市名
    7-6 三个出口
    TypeError: module() takes at most 2 arguments (3 given)
  • 原文地址:https://www.cnblogs.com/handsome-zyc/p/13616505.html
Copyright © 2011-2022 走看看