记录编号 294507 评测结果 AAAAAAAAAA
题目名称 [NOIP 2010]引水入城 最终得分 100
用户昵称 Gravatar安呐一条小咸鱼。 是否通过 通过
代码语言 C++ 运行时间 0.721 s
提交时间 2016-08-12 13:46:19 内存使用 10.08 MiB
显示代码纯文本
  1. #include<queue>
  2. #include<stack>
  3. #include<cstdio>
  4. #include<cstring>
  5. #include<iostream>
  6. #include<algorithm>
  7. #define maxn 1510
  8. using namespace std;
  9. int h[maxn][maxn];
  10. int n,m;
  11. int sum;
  12. int l[maxn],r[maxn],dp[maxn];
  13. bool f,flag[maxn][maxn],judge[maxn];
  14. /* h储存读入
  15. sum用来储存多少不能供水 f用来判断能否全部供水;
  16. flag用于dfs时判是否visited
  17. l,r 记录的是以第一行的i为起点 到的最后一行的连续的点的l-r区间
  18. */
  19. void dfs(int s,int x,int y)//s是从第一行开始最多能到最后一行多少个点 坐标为h[x][y]
  20. {
  21. if(x==n)
  22. {
  23. judge[y]=1;//到了第n行 可以到y 更新judge
  24. if(y<l[s]||!l[s])l[s]=y;//如果l[s]=0更新 或者l[s]<y
  25. if(y>r[s])r[s]=y;//这里记录的l,r数组记录的是以第一行的s为起点能到的最后一行的连续的点的l-r区间用于求第二问
  26. }
  27. int hi=h[x][y];flag[x][y]=1;
  28. if(x<n && h[x+1][y]<hi && !flag[x+1][y])dfs(s,x+1,y);//floodfill
  29. if(x>1 && h[x-1][y]<hi && !flag[x-1][y])dfs(s,x-1,y);
  30. if(y<m && h[x][y+1]<hi && !flag[x][y+1])dfs(s,x,y+1);
  31. if(y>1 && h[x][y-1]<hi && !flag[x][y-1])dfs(s,x,y-1);
  32. }
  33. int main(){
  34. freopen("flow.in","r",stdin);
  35. freopen("flow.out","w",stdout);
  36. scanf("%d%d",&n,&m);
  37. for(int i=1;i<=n;i++)
  38. {
  39. for(int j=1;j<=m;j++)
  40. {
  41. scanf("%d",&h[i][j]);
  42. }
  43. }
  44. //对于第一问 dfs可以解决
  45. for(int i=1;i<=m;i++)
  46. {
  47. if(i>1 && h[1][i]<h[1][i-1])continue;//为什么要continue呢? 如果这个点比旁边的两个任何一个水站低,那么他们可以
  48. //给自己,就不用dfs这个点了,这就可以避免重复计算
  49. if(i<m && h[1][i]<h[1][i+1])continue;//判断第一行 因为第一行直接可以得到水 判断i边界
  50. memset(flag,0,sizeof(flag));//清空上次的标记
  51. dfs(i,1,i);//找出能到达的最后一行最多的点
  52. }
  53. for(int i=1;i<=m;i++)
  54. {
  55. if(!judge[i])
  56. {
  57. sum++;f=1;//如果最后一行有没到的 那么就sum++,通知f=1;
  58. }
  59. }
  60. if(f){//没到
  61. puts("0");printf("%d\n",sum);
  62. fclose(stdin);fclose(stdout);
  63. }
  64. else
  65. {
  66. puts("1");
  67. }
  68. //开始dp求第二问
  69. /*
  70. dp之前要先证明一个东西QwQ 即通过dfs找出来的到达的最后一行的点都是连续的,这样我们dfs记录的l,r数组才敢用
  71. 证明: 假设最后一行的这些点不是连续的 那么我们随意取l-r中间一个不能到的点为x ,那么x一定比旁边的点都高 ,
  72. 那么你怎么可能有解??? 直接输出0别求第二问了;
  73. 所以证明完了之后变成了dp求线段覆盖型的动归
  74. */
  75. for(int i=1;i<=m;i++)
  76. {
  77. for(int j=l[i];j<=r[i];j++)
  78. {
  79. if(dp[j]>dp[ l[i]-1 ]+1 || !dp[j])//dp[j]如果是0那么肯定要更新啊,
  80. {
  81. dp[j]=dp[ l[i]-1 ]+1;//到达n行j列所需的机器> 到达n行l[i]-1列所需的机器+1 更新QwQ;
  82. }
  83. }
  84. }
  85. printf("%d",dp[m]);//到第m列最少用几台机器
  86. fclose(stdin);
  87. fclose(stdout);
  88. return 0;
  89. }