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;
    }
  • 相关阅读:
    hdu 4027 Can you answer these queries? 线段树
    ZOJ1610 Count the Colors 线段树
    poj 2528 Mayor's posters 离散化 线段树
    hdu 1599 find the mincost route floyd求最小环
    POJ 2686 Traveling by Stagecoach 状压DP
    POJ 1990 MooFest 树状数组
    POJ 2955 Brackets 区间DP
    lightoj 1422 Halloween Costumes 区间DP
    模板 有源汇上下界最小流 loj117
    模板 有源汇上下界最大流 loj116
  • 原文地址:https://www.cnblogs.com/handsome-zyc/p/13616505.html
Copyright © 2011-2022 走看看