记录编号 294507 评测结果 AAAAAAAAAA
题目名称 [NOIP 2010]引水入城 最终得分 100
用户昵称 Gravatar安呐一条小咸鱼。 是否通过 通过
代码语言 C++ 运行时间 0.721 s
提交时间 2016-08-12 13:46:19 内存使用 10.08 MiB
显示代码纯文本
#include<queue>
#include<stack>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define maxn 1510
using namespace std;
int h[maxn][maxn];
int n,m;
int sum;
int l[maxn],r[maxn],dp[maxn];
bool f,flag[maxn][maxn],judge[maxn];
/* h储存读入 
sum用来储存多少不能供水 f用来判断能否全部供水; 
flag用于dfs时判是否visited 
l,r 记录的是以第一行的i为起点 到的最后一行的连续的点的l-r区间
*/
void dfs(int s,int x,int y)//s是从第一行开始最多能到最后一行多少个点  坐标为h[x][y] 
{
	if(x==n)
	{
		judge[y]=1;//到了第n行 可以到y 更新judge 
		if(y<l[s]||!l[s])l[s]=y;//如果l[s]=0更新 或者l[s]<y 
		if(y>r[s])r[s]=y;//这里记录的l,r数组记录的是以第一行的s为起点能到的最后一行的连续的点的l-r区间用于求第二问 
	}
	int hi=h[x][y];flag[x][y]=1;
	if(x<n && h[x+1][y]<hi && !flag[x+1][y])dfs(s,x+1,y);//floodfill 
	if(x>1 && h[x-1][y]<hi && !flag[x-1][y])dfs(s,x-1,y);
	if(y<m && h[x][y+1]<hi && !flag[x][y+1])dfs(s,x,y+1);
	if(y>1 && h[x][y-1]<hi && !flag[x][y-1])dfs(s,x,y-1);
}
int main(){
	freopen("flow.in","r",stdin);
	freopen("flow.out","w",stdout); 
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			scanf("%d",&h[i][j]);
		}
	}
	//对于第一问 dfs可以解决
	for(int i=1;i<=m;i++)
	{		
		if(i>1 && h[1][i]<h[1][i-1])continue;//为什么要continue呢? 如果这个点比旁边的两个任何一个水站低,那么他们可以
		//给自己,就不用dfs这个点了,这就可以避免重复计算  
		if(i<m && h[1][i]<h[1][i+1])continue;//判断第一行   因为第一行直接可以得到水  判断i边界 
		memset(flag,0,sizeof(flag));//清空上次的标记 
		dfs(i,1,i);//找出能到达的最后一行最多的点 
	}
	for(int i=1;i<=m;i++)
	{
		if(!judge[i])
		{
			sum++;f=1;//如果最后一行有没到的 那么就sum++,通知f=1; 
		}
	} 
	if(f){//没到 
		puts("0");printf("%d\n",sum);
		fclose(stdin);fclose(stdout);
	}
	else
	{
		puts("1");
	}
	//开始dp求第二问 
	/*
	 dp之前要先证明一个东西QwQ  即通过dfs找出来的到达的最后一行的点都是连续的,这样我们dfs记录的l,r数组才敢用
	 证明: 假设最后一行的这些点不是连续的  那么我们随意取l-r中间一个不能到的点为x ,那么x一定比旁边的点都高 ,
	 那么你怎么可能有解??? 直接输出0别求第二问了; 
	 所以证明完了之后变成了dp求线段覆盖型的动归 
	*/ 
	for(int i=1;i<=m;i++)
	{
		for(int j=l[i];j<=r[i];j++)
		{
			if(dp[j]>dp[ l[i]-1 ]+1 || !dp[j])//dp[j]如果是0那么肯定要更新啊, 
			{
				dp[j]=dp[ l[i]-1 ]+1;//到达n行j列所需的机器> 到达n行l[i]-1列所需的机器+1 更新QwQ; 
			}
		}
	}
	printf("%d",dp[m]);//到第m列最少用几台机器 
	fclose(stdin);
	fclose(stdout);
	return 0;
}