【动态规划】[luoguP1736]创意吃鱼法

题目

发表了题解。。

我真的不知道我写的搜索还是DP
反正都差不多吧 - -
怎么搞呢
首先我们用三个数组 map[][]存图 f[][]用来存如果矩阵的对角线是从左上到右下的话 能取得的最大对角线长度 dp[][]则是同理的右上到左下的矩阵
因为每一个有鱼的位置一开始本身就是一个矩阵 所以初始化当map[i][j]=1的时候 dp[i][j]和f[i][j]都为1
然后在我们枚举一个k 往前找 看看有没有多余的1 因为我们要让矩阵尽量的大且题目要求这个矩阵除了对角线之外其他地方都不能有1的 且k只需要枚举到f(dp)[i - 1][j - 1]因为再往前的之前搞f(dp)[i - 1][j - 1]已经枚举过了 再枚举反而会出乱子 然后就是如果满足!map[i - k][j] && !map[i][j - k] && map[i - k][j - k]那么这个矩阵就可以有i-k~i j-k~j那么大 用一个tmp来记录当前对角线增长了多少 最后f(dp)[i][j]再+=tmp一下 就完成了 这样保证对于每一个有鱼的点都能统计到以它为末端的最大的对角线是左上到右下的正方形或者对角线是右上到左下的正方形的对角线长度(没错 我语文很差)
在过程中ans不断更新最大值 最后输出

代码如下



#include<iostream>
#include<cstdio>
#include<cctype>

    using namespace std;
    #define in = read();
    typedef long long ll;
    typedef unsigned int ui;
    const ll size = 2500 + 10;

        int n , m;
        int map[size][size];
        int ans , tmp , tmp2;
        int f[size][size] , dp[size][size];

inline ll read(){
        ll num = 0 , f = 1;    char ch = getchar();

        while(!isdigit(ch)){
                if(ch == '-')   f = -1;
                ch = getchar();
        }
        while(isdigit(ch)){
                num = num*10 + ch - '0';
                ch = getchar();
        }

        return num*f;
}

int main(){
        n in;    m in;
        for(register int i=1;i<=n;i++)
                for(register int j=1;j<=m;j++){
                        map[i][j] in;
                        if(map[i][j]){
                                f[i][j] = 1;
                                dp[i][j] = 1;
                                ans = 1;
                        }
                }

        for(register int i=1;i<=n;i++)
                for(register int j=1;j<=m;j++){
                        if(map[i][j] && map[i - 1][j - 1]){
                                for(register int k=1;k<=f[i - 1][j - 1];k++){
                                        if(!map[i - k][j] && !map[i][j - k] && map[i - k][j - k])
                                                tmp ++;
                                        else    break;
                                }
                                f[i][j] += tmp;
                                ans = max(ans , f[i][j]);
                                tmp = 0;
                        }
                }
        for(register int i=1;i<=n;i++)
                for(register int j=1;j<=m;j++){
                        if(map[i][j] && map[i - 1][j + 1]){
                                for(register int k=1;k<=dp[i - 1][j + 1];k++){
//                                        cout<<k<<" "<<map[i - 1][j + 1] + 1<<" " <<i<<" "<<j<<endl;
                                        if(!map[i - k][j] && !map[i][j + k] && map[i - k][j + k])
                                                tmp ++;
                                        else    break;
                                }
                                dp[i][j] += tmp;
                                ans = max(ans , dp[i][j]);
                                tmp = 0;
                        }
                }
/*
        cout<<endl;
        for(register int i=1;i<=n;i++){
                for(register int j=1;j<=m;j++)
                        cout<<f[i][j]<<" ";
                cout<<endl;
        }
        cout<<endl;
        for(register int i=1;i<=n;i++){
                for(register int j=1;j<=m;j++)
                        cout<<dp[i][j]<<" ";
                cout<<endl;
        }*/
        printf("%d" , ans);
}
/*
4 6
0 0 1 0 1 0
0 1 0 1 0 0
1 0 0 0 1 1
0 1 0 1 1 0

10 10
0 0 1 0 1 0 1 1 1 1 
1 1 1 0 1 0 0 0 0 1
0 0 0 0 0 0 0 1 0 1
0 0 0 0 0 0 1 0 1 1
0 0 0 0 0 1 0 0 1 0
0 0 0 0 1 0 0 0 1 1
0 0 0 1 0 0 0 0 1 1
0 0 1 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0 1 1
1 0 0 0 0 0 0 0 1 0
*/


//COYG
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值