比赛 |
练习12 |
评测结果 |
AAAAAAAAAA |
题目名称 |
引水入城 |
最终得分 |
100 |
用户昵称 |
NVIDIA |
运行时间 |
0.049 s |
代码语言 |
C++ |
内存使用 |
0.31 MiB |
提交时间 |
2017-06-30 13:46:02 |
显示代码纯文本
/*
NAME:槿柒
LANG:C++
TIME:0.5S
PID:4819
*/
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
inline int read()
{
int x,f=1;char ch;
while(ch=getchar(),!isdigit(ch))if(ch=='-')f=-1;x=ch-48;
while(ch=getchar(),isdigit(ch))x=x*10+ch-48;return x*f;
}
const int maxn=510;
int n,m,a[maxn][maxn],l[maxn],r[maxn],f[maxn],dx[5]={0,0,1,-1},dy[5]={1,-1,0,0};//f[i]:表示到第n行第i列所建的最小蓄水厂
bool flag[maxn][maxn],vis[maxn];
inline void Dfs(int s,int x,int y){
if(x==n){
vis[y]=1;//记录总深搜能搜到的点,不可清空
if(!l[s]||l[s]>y)l[s]=y;//l[s]表示如果以s建立蓄水厂,能扩展的左边界的最大值
if(r[s]<y)r[s]=y;//同理,r[s]表示如果以s建立蓄水厂,能扩展的右边界的最大值
}
flag[x][y]=1;
for(int i=0;i<4;i++){
int xx=x+dx[i],yy=y+dy[i];//传说中的floodfill……
if(xx<1||xx>n||yy<1||yy>m)continue;
if(!flag[xx][yy] && a[xx][yy]<a[x][y])Dfs(s,xx,yy);
}
}
inline int Nymph()
{
freopen("flow.in","r",stdin);
freopen("flow.out","w",stdout);
n=read();m=read();
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)a[i][j]=read();
for(int i=1;i<=m;i++){
if(a[1][i]<a[1][i-1])continue;//剪枝,不然会暴。如果当前点高度<之前一列的点,那么它的水直接由i-1转移来,不必再搜索了
if(a[1][i]<a[1][i+1])continue;
memset(flag,0,sizeof(flag));//注意清空~
Dfs(i,1,i);//第一问:深搜即可,dfs(i,1,i)代表如果第i个建蓄水厂,当前坐标为(1,i)
}
int cnt=0;
for(int i=1;i<=m;i++)if(vis[i])cnt++;
if(cnt<m){
printf("0\n%d\n",m-cnt);return 0;
}
printf("1\n");
for(int i=1;i<=m;i++){ //枚举第一行如果i建蓄水厂
for(int j=l[i];j<=r[i];j++){ //枚举以i建蓄水厂能伸展的左右边界
if(!f[j])f[j]=f[l[i]-1]+1;//预处理
else f[j]=min(f[j],f[l[i]-1]+1);//由最左列前面一列转移过来的最小蓄水厂值+1所得的答案与本身比较
}
}
printf("%d\n",f[m]);
}
int nymph=Nymph();
int main(){;}