题解 P2701 【[USACO5.3]巨大的牛棚Big Barn】

· · 题解

思路:

这道题很水,但很适合dp初学者做!(瞎扯一下

先写动态转移方程,待会解释

f_{i,j}=min\{f_{i-1,j},f_{i,j-1},f_{i-1,j-1}\}+1

(a_{i,j}!=\#)

解释:

用**jio**指头想想就能知道,$f_{i,j}$是由左、上、左上方向来的 用$min$的原因是,如果用$max$,三个方向的正方形可能会碰到树,以及其它情况(蒟蒻表达不出来,看栗子~). 拿样例解释: ```pascal . . . . . . . . . # . . . # . . . . . . . . . . . . . . . . . . . . . . . . . . . . # . . . . . . . . . . . . . . . . . . . . . ``` 用$max$: ```pascal 1 1 1 1 1 1 1 1 2 0 2 3 4 0 2 3 3 4 5 6 7 8 9 10 4 5 6 7 8 9 10 11 5 6 7 8 9 10 11 12 6 7 0 9 10 11 12 13 8 9 10 11 12 13 14 15 9 10 11 12 13 14 15 16 ``` 实际: ```pascal 1 1 1 1 1 1 1 1 1 0 1 2 2 0 1 2 1 1 1 2 3 1 1 2 ``` (前几行,我累了。。。) 对比一下,用$max$根本不可能 ## 代码 ### 创建美好洛谷,切勿Ctrl+C c++党这里↓ ```cpp #inculde<bits/stdc++.h> using namespace std; int n,t; int f[1010][1010]; int ans; int main() { scanf("%d%d",&n,&t); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) f[i][j]=1; //边界条件哦 while(t--) { int x,y; scanf("%d%d",&x,&y); f[x][y]=0; //树的位置打零 } for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) //i和j千万不要从2开始哦 { if(f[i][j]==0)continue; f[i][j]=min(min(f[i-1][j],f[i][j-1]),f[i-1][j-1])+1; //转移方程哦 ans=max(ans,f[i][j]); //更新目标 } } printf("%d",ans); //输出yeah return 0; //。。。yeah } ``` --- p党在这里哦~ ```pascal var f:array[0..1010,0..1010]of longint;//注意是从0开始 x,y,i,j,n,t,ans:longint; function min(a,b:longint):longint; begin if a>b then exit(b) else exit(a); end; function mx(a,b:longint):longint; begin if a<b then exit(b) else exit(a); end; begin readln(n,t); for i:=1 to n do for j:=1 to n do f[i,j]:=1; //边界条件 for i:=1 to t do begin readln(x,y); f[x,y]:=0; //树的位置打零 end; for i:=1 to n do for j:=1 to n do begin if f[i,j]=0 then continue; f[i,j]:=min(min(f[i-1,j],f[i,j-1]),f[i-1,j-1])+1; //转移方程 ans:=max(ans,f[i,j]); //更新目标 end; writeln(ans); //yeah~ end. ``` 希望你喜欢(暗示点赞