zoukankan      html  css  js  c++  java
  • 【NOIP2010提高组T4】引水入城-搜索+DP

    测试地址:引水入城

    做法:一开始可以把最上面一排都看成有水,用一次Floodfill判断是否有解,如果最下面一排没有被全部覆盖则无解。可以证明,如果有解,则从上面一个点流水到下面一定会覆盖下面的一个区间。用2次DFS找寻上面每个点的可覆盖区间的左右端点,在一次DFS中,走过的点不用再走,因为从这个点扩展到的点的端点肯定已经确定了。最后用一次DP找最小区间覆盖,设f[i]为要覆盖前i个点至少要建的蓄水厂数,则状态转移方程为:f[i]=f[left[v]-1]+1(left[v]<=i&&right[v]>=i),其中left[v]和right[v]表示上方第v个点所覆盖的区间的左右端点。

    代码:

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    using namespace std;
    int n,m,h[510][510],l[510],r[510],ans,f[510];
    bool vis[510][510];
    typedef pair<int,int> p;
    
    bool ava(int x,int y,int sx,int sy)
    {
      return x>=1&&x<=n&&y>=1&&y<=m&&!vis[x][y]&&h[x][y]<h[sx][sy];
    }
    
    bool ava2(int x,int y,int sx,int sy)
    {
      return x>=1&&x<=n&&y>=1&&y<=m&&!vis[x][y]&&h[x][y]>h[sx][sy];
    }
    
    void bfs()
    {
      queue<p> q;
      memset(vis,0,sizeof(vis));
      for(int i=1;i<=m;i++)
        vis[1][i]=1,q.push(make_pair(1,i));
      while(!q.empty())
      {
        int x=q.front().first,y=q.front().second;
    	q.pop();
    	if (ava(x-1,y,x,y)) q.push(make_pair(x-1,y)),vis[x-1][y]=1;
    	if (ava(x,y-1,x,y)) q.push(make_pair(x,y-1)),vis[x][y-1]=1;
    	if (ava(x+1,y,x,y)) q.push(make_pair(x+1,y)),vis[x+1][y]=1;
    	if (ava(x,y+1,x,y)) q.push(make_pair(x,y+1)),vis[x][y+1]=1;
      }
    }
    
    void dfsl(int x,int y,int i)
    {
      vis[x][y]=1;
      if (x==1) l[y]=i;
      if (ava2(x-1,y,x,y)) dfsl(x-1,y,i);
      if (ava2(x,y-1,x,y)) dfsl(x,y-1,i);
      if (ava2(x+1,y,x,y)) dfsl(x+1,y,i);
      if (ava2(x,y+1,x,y)) dfsl(x,y+1,i);
    }
    
    void dfsr(int x,int y,int i)
    {
      vis[x][y]=1;
      if (x==1) r[y]=i;
      if (ava2(x-1,y,x,y)) dfsr(x-1,y,i);
      if (ava2(x,y-1,x,y)) dfsr(x,y-1,i);
      if (ava2(x+1,y,x,y)) dfsr(x+1,y,i);
      if (ava2(x,y+1,x,y)) dfsr(x,y+1,i);
    }
    
    int main()
    {
      scanf("%d%d",&n,&m);
      for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
    	  scanf("%d",&h[i][j]);
      
      bfs();
      ans=0;
      for(int i=1;i<=m;i++)
        if (!vis[n][i]) ans++;
      if (ans>0) {printf("0
    %d",ans);return 0;}
      
      memset(vis,0,sizeof(vis));
      for(int i=1;i<=m;i++)
        if (!vis[n][i]) dfsl(n,i,i);
      memset(vis,0,sizeof(vis));
      for(int i=m;i>=1;i--)
        if (!vis[n][i]) dfsr(n,i,i);
      
      f[0]=0,f[1]=1;
      for(int i=2;i<=m;i++)
      {
        f[i]=999999999;
        for(int j=1;j<=m;j++)
    	{
          if (l[j]<=i&&r[j]>=i) f[i]=min(f[i],f[l[j]-1]+1);
          else if (l[j]>i) break;
    	}
      }
      
      printf("1
    %d",f[m]);
      
      return 0;
    }


  • 相关阅读:
    Android code wiki
    Android 屏蔽ScrollView滑动操作
    Android PorterDuff.Mode
    微信小程序开发——小程序分享转发
    支付宝小程序开发之与微信小程序不同的地方
    微信小程序快速移植支付宝小程序
    微信小程序开发——小程序API获取用户位置及异常流处理完整示例
    微信小程序开发——开发者工具中素材管理功能使用的注意事项
    js数组排序实用方法集锦
    chrome谷歌浏览器常用快捷键搜集整理
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793879.html
Copyright © 2011-2022 走看看