题意简化
传送门
给定一个矩阵,每个点有高度,矩阵的第一行的每个点都可以修蓄水池,其他点可以修输水站,输水站只能利用高度差来取水,试问最后一行能否都有水
可以则要求最小化蓄水池,不能则求最小化最后一行的干旱点
题解
首先有个很重要的性质,是可以推出来的:
第一行的每个点所能管辖到的最后一行的点一定是连续的
若不是连续的,那么中间断开的点一定不会有其他水源
知道了这个就可以很轻松的搜索出最后一行是否能全部覆盖
然后我们再想想如何把答案最小化
记忆化搜索,嗯
代码
#include<bits/stdc++.h>
#define rnt register int
#define ii inline
#define get getchar();
#define ll long long
using namespace std;
int n,m,a[501][501],r[501],l[501];
bool f[501][501];
ii ll read()
{
int x=1,k=0;char ch;
ch=get;while(ch!='-'&&(ch>'9'||ch<'0'))ch=get;
if(ch=='-')x=-1,ch=get;
while(ch>='0'&&ch<='9')k=k*10+(ch-'0'),ch=get;;
return x*k;
}
int xx[4]={0,0,1,-1},yy[4]={1,-1,0,0},q[501];
int ans1=0;bool ans[501];
ii void dfs(rnt x,rnt y,rnt p)
{
f[x][y]=1;
if(x==n)
{
ans[y]=1;
r[p]=max(r[p],y);
l[p]=min(l[p],y);
}
for(rnt i=0;i<=3;i++)
{
rnt x1=x+xx[i],y1=y+yy[i];
if(x1>0&&x1<=n&&y1>0&&y1<=m)
if(a[x1][y1]<a[x][y]&&f[x1][y1]==0)
{
dfs(x1,y1,p);
}
}
}
int main()
{
n=read(),m=read();
for(rnt i=1;i<=m;i++)l[i]=40001,q[i]=40001;
for(rnt i=1;i<=n;i++)
for(rnt j=1;j<=m;j++)
a[i][j]=read();
for(rnt i=1;i<=m;i++)
if(a[1][i-1]<=a[1][i]&&a[1][i+1]<=a[1][i]){
dfs(1,i,i);memset(f,0,sizeof(f));}
for(rnt i=1;i<=m;i++)
if(ans[i]==0)ans1++;
if(ans1)
{
cout<<0<<endl<<ans1;
return 0;
}
for(rnt i=1;i<=m;i++)//最后一行
for(rnt j=1;j<=m;j++)//第一行
{
if(i<=r[j]&&i>=l[j])q[i]=min(q[i],q[l[j]-1]+1);
}
cout<<1<<endl<<q[m];
}