P1736 创意吃鱼法 (动态规划)
题目描述
回到家中的猫猫把三桶鱼全部转移到了她那长方形大池子中,然后开始思考:到底要以何种方法吃鱼呢(猫猫就是这么可爱,吃鱼也要想好吃法 ^_*)。她发现,把大池子视为01矩阵(0表示对应位置无鱼,1表示对应位置有鱼)有助于决定吃鱼策略。
在代表池子的01矩阵中,有很多的正方形子矩阵,如果某个正方形子矩阵的某条对角线上都有鱼,且此正方形子矩阵的其他地方无鱼,猫猫就可以从这个正方形子矩阵“对角线的一端”下口,只一吸,就能把对角线上的那一队鲜鱼吸入口中。
猫猫是个贪婪的家伙,所以她想一口吃掉尽量多的鱼。请你帮猫猫计算一下,她一口下去,最多可以吃掉多少条鱼?
输入输出格式
输入格式:有多组输入数据,每组数据:
第一行有两个整数n和m(n,m≥1),描述池塘规模。接下来的n行,每行有m个数字(非“0”即“1”)。每两个数字之间用空格隔开。
对于30%的数据,有n,m≤100
对于60%的数据,有n,m≤1000
对于100%的数据,有n,m≤2500
输出格式:只有一个整数——猫猫一口下去可以吃掉的鱼的数量,占一行,行末有回车。
输入输出样例
4 6 0 1 0 1 0 0 0 0 1 0 1 0 1 1 0 0 0 1 0 1 1 0 1 0
3
说明
右上角的
1 0 0
0 1 0
0 0 1
Solution
一开始以为是道DP水题...
自信满满:
状态很好定义:
f [ i ] [ j ] 代表吃到 ( i , j )这个点的时候最多吃多少.
转移也很好转移,直接从左斜线和右斜线转移过来.
20分的代码:
int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&c[i][j]); f[1][1]=c[1][1]; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { f[i][j]=c[i][j]; if(i>1&&j>1) if(c[i][j]&&c[i-1][j-1]) f[i][j]=max(f[i][j],c[i][j]+f[i-1][j-1]); ans=max(ans,f[i][j]); } memset(f,0,sizeof(f)); f[1][m]=1; for(int i=1;i<=n;i++) for(int j=m;j>=1;j--) { f[i][j]=c[i][j]; if(i>1&&j<m) if(c[i][j]&&c[i+1][j-1]) f[i][j]=max(f[i][j],c[i][j]+f[i+1][j-1]); ans=max(ans,f[i][j]); } cout<<ans<<endl; }
然后,才发现自己有几个限制没注意到...一直20分.
我一开始就有一个误区,即一开始就把所有状态混在一起.
打得心态崩溃,于是发现还需要两个数组来记录
当前这个点四周没有1的正方形的最大面积.
然后其实应该分两个情况来做才好.因为:
0 0 1
0 1 0
0 0 1
像这样的情况是不能转移的.
但是用我刚才的状态做,很坑... 所以处理两遍是最好的方式.
左斜处理一遍,右斜处理一遍.
事实证明,题目真的要仔细看...
代码
#include<bits/stdc++.h> using namespace std; const int maxn=2508; int n,m,ans; int c[maxn][maxn],f[maxn][maxn]; int f1[maxn][maxn],f2[maxn][maxn]; int main() { scanf("%d%d",&n,&m); f[1][1]=c[1][1]; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { f[i][j]=c[i][j]; scanf("%d",&c[i][j]); if(!c[i][j]) f1[i][j]=f1[i][j-1]+1, f2[i][j]=f2[i-1][j]+1; if(c[i][j]) f[i][j]=min(f[i-1][j-1],min(f1[i][j-1],f2[i-1][j]))+1; ans=max(ans,f[i][j]); } memset(f,0,sizeof(f)); memset(f1,0,sizeof(f1)); memset(f2,0,sizeof(f2)); for(int i=1;i<=n;i++) for(int j=m;j>=1;j--) { f[i][j]=c[i][j]; if(!c[i][j]) f1[i][j]=f1[i][j+1]+1, f2[i][j]=f2[i-1][j]+1; if(c[i][j]) f[i][j]=min(f[i-1][j+1],min(f1[i][j+1],f2[i-1][j]))+1; ans=max(ans,f[i][j]); } cout<<ans<<endl; }