zoj 2067 dp

求白方块的个数,这个用的是N^3的算法,之后我在woj1012中会更新N^2 的算法

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1067

/*
    题目:经典DP
    分析:状态方程 f(i,j),为以 i,j为右下角的 rect的个数,然后求和即可。
            预处理,计算每行到位置 j的 rect的个数,然后从下向上计算,
            保存长度最小的 rect个数即可(大的会被截取)。
    说明:先计算一维,在利用一维求解二维,其实都是在求解一维。
            本题可以利用单调队列,做简单的优化,但是基于概率的。
            记录到每个位置上面的最近的小于当前长度节点,然后跳着查找。
            如果存在相邻的非递增序即可优化,不过系数有点大,与数据状态有关。
*/
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
char maps[ 105 ][ 105 ];
int  line[ 105 ][ 105 ];
int  rect[ 105 ][ 105 ];
int main()
{
    freopen("in.cpp", "r", stdin);
    //freopen("out.cpp", "w", stdout);
    int n;
    while(scanf("%d",&n) != EOF)
    {
        int i,j,k,ans=0;
        for(i=1;i<=n;i++) scanf("%s",&maps[i][1]);//scanf可以这样读取输入,长见识了

        memset( line, 0, sizeof( line ) );
        memset( rect, 0, sizeof( rect ) );
        //第i行包含j位置的连续白方块个数
        for(i=1;i<=n;i++)
        for(j=1;j<=n;j++)
           if(maps[i][j]=='.') line[i][j]=line[i][j-1]+1;
        //包含i,j位置的白方块个数
        for(i=1;i<=n;i++)
        for(j=1;j<=n;j++)
        {
            int minl=line[i][j];
            for(k=i;k>0;k++)
            {
                if(minl==0) break;
                if(minl>line[k][j]) minl=line[k][j];
                rect[k][j] +=minl;
            }
        }
        for(i=1;i<=n;i++)
        for(j=1;j<=n;j++) ans +=rect[i][j];
        printf("%d\n",ans);

    }
    return 0;
}

使用cin,cout输入输出也行

/*
    题目:经典DP
    分析:状态方程 f(i,j),为以 i,j为右下角的 rect的个数,然后求和即可。
            预处理,计算每行到位置 j的 rect的个数,然后从下向上计算,
            保存长度最小的 rect个数即可(大的会被截取)。
    说明:先计算一维,在利用一维求解二维,其实都是在求解一维。
            本题可以利用单调队列,做简单的优化,但是基于概率的。
            记录到每个位置上面的最近的小于当前长度节点,然后跳着查找。
            如果存在相邻的非递增序即可优化,不过系数有点大,与数据状态有关。
*/
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
char maps[ 105 ][ 105 ];
int  line[ 105 ][ 105 ];
int  rect[ 105 ][ 105 ];
int main()
{
    //freopen("in.cpp", "r", stdin);
    //freopen("out.cpp", "w", stdout);
    int n;
    while(cin>>n)
    {
        //cout<<n<<endl;
        int i,j,k,ans=0;
        for(i=1;i<=n;i++)
        for(j=1;j<=n;j++) cin>>maps[i][j];
        /*
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=n;j++) cout<<maps[i][j];
            cout<<endl;
        }
        */

        memset( line, 0, sizeof( line ) );
        memset( rect, 0, sizeof( rect ) );
        //第i行包含j位置的连续白方块个数
        for(i=1;i<=n;i++)
        for(j=1;j<=n;j++)
           if(maps[i][j]=='.') line[i][j]=line[i][j-1]+1;
        //包含i,j位置的白方块个数
        for(i=1;i<=n;i++)
        for(j=1;j<=n;j++)
        {
            int minl=line[i][j];
            for(k=i;k>0;k++)
            {
                if(minl==0) break;
                if(minl>line[k][j]) minl=line[k][j];
                rect[k][j] +=minl;
            }
        }
        for(i=1;i<=n;i++)
        for(j=1;j<=n;j++) ans +=rect[i][j];
        cout<<ans<<endl;

    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值