NOIP2010【引水入城】

来源:互联网 发布:软件设计方案 编辑:程序博客网 时间:2024/04/27 17:40

【题解】

  起先搜索将整张图遍历一遍,求出每个第一行的格子能覆盖到的最后一行的最左和最右的格子用g[1][j][0/1]表示(刚开始用广搜(注释的部分),每次求一个格子都遍历一边(比较蠢)复杂度是o(n*m^2)只能过七十分,后来改成了深搜只遍历一遍算出所有,复杂度o(n*m))

  算出了上述的东西后,就是一个经典的区间覆盖动归(用第一行覆盖最后一行)

  f[i]表示最后一行前i的格子都已经被覆盖时所需要的第一行格子的最小值

  f[i]=min(f[i],f[g[1][j][0]-1]+1)
  详见代码

   

#include <algorithm>#include <iostream>#include <cstdlib>#include <cstring>#include <string>#include <cstdio>#include <queue>#include <ctime>#include <cmath>#include <vector>using namespace std;int i,j,k,l,m,n;int f[505],flag[505][505],q[50000][2],g[505][505][2],h,t,a[505][505],xx[4]={-1,0,1,0},yy[4]={0,1,0,-1};void dfs(int x,int y)  {int x2,y2;flag[x][y]=1;if (x==n) g[x][y][0]=g[x][y][1]=y;for (int i=0;i<4;i++)  {x2=x+xx[i];y2=y+yy[i];if (a[x][y]>a[x2][y2])  {    if (!flag[x2][y2]) dfs(x2,y2);g[x][y][0]=min(g[x][y][0],g[x2][y2][0]);g[x][y][1]=max(g[x][y][1],g[x2][y2][1]);  }   }    }int main()  {  scanf("%d%d",&n,&m);  for (i=1;i<=n;i++) for (j=1;j<=m;j++) scanf("%d",&a[i][j]);  for (i=0;i<=m;i++) a[0][i]=a[n+1][i]=1e9;  for (i=0;i<=n;i++) a[i][0]=a[i][m+1]=1e9;  for (i=1;i<=n;i++) for (j=1;j<=m;j++) g[i][j][0]=m+1,g[i][j][1]=0;  /*for (i=1;i<=m;i++)    {    t++;q[t][0]=1;q[t][1]=i;flag[1][i]=1;      }    for (;h<t;)      {      h++;      //if (q[h][0]==n) g[i][0]=min(g[i][0],q[h][1]);g[i][1]=max(g[i][1],q[h][1]);      for (j=0;j<4;j++)        if (a[q[h][0]+x[j]][q[h][1]+y[j]]<a[q[h][0]][q[h][1]]&&flag[q[h][0]+x[j]][q[h][1]+y[j]]==0)          {flag[q[h][0]+x[j]][q[h][1]+y[j]]=i;t++;q[t][0]=q[h][0]+x[j];q[t][1]=q[h][1]+y[j];g[q[h][0]][q[h][1]][0]=min(g[q[h][0]][q[h][1]][0]}  }*/    for (i=1;i<=m;i++) dfs(1,i);l=0;for (i=1;i<=m;i++)  if (flag[n][i]==0) l++;if (l>0) {printf("0\n%d",l);return 0;}    for (i=1;i<=m;i++)      {        f[i]=1e9;        for (j=1;j<=m;j++)            if (i>=g[1][j][0]&&i<=g[1][j][1])                f[i]=min(f[i],f[g[1][j][0]-1]+1);      }printf("1\n%d",f[m]);    }



0 0
原创粉丝点击