uva 10593 Kites(dp)

本文解决了一个关于从带有孔洞的方形纸张中切割不同大小风筝的问题。通过动态规划的方法,作者展示了如何计算出所有有效的风筝形状数量,包括正方形和菱形风筝。详细解释了算法实现过程,并提供了关键代码片段,帮助读者理解如何通过避免重复计算来优化算法效率。

Problem E

Kites

Time Limit

4 Seconds

 

The season of flying kites is well ahead. So what? Let us make an inventory for kites. We are given a square shaped sheet of paper. But many parts of this are already porous. Your challenge here is to count the total number of ways to cut a kite of any size from this sheet. By the way, the kite itself can't be porous :-) AND..................it must be either square shaped or diamond shaped.

 
                        x
           x           xxx           xxx           xxx
          xxx         xxxxx          xxx           x.x         x
           x           xxx           xxx           xxx
                        x

In the above figure first three are valid kites but not next two.

 

Input

Input contains an integer n (n ≤ 500), which is the size of the sheet. Then follows n lines each of which has n characters ('x' or '.'). Here the dotted parts resemble the porous parts of the sheet. Input is terminated by end of file.

 

Output

Output is very simple. Only print an integer according to the problem statement for each test case in a new line.

 

Sample Input

Output for Sample Input

4
.xx.
xxxx
.xx.
.x..
3
xxx
xxx
xxx

4

6

 

Problemsetter: Mohammad Sajjad Hossain

Bangladesh University of Engineering and Technology

直接暴力枚举应该会超时,怎么办呢?实际上暴力枚举的过程中做了很多重复的计算,我如果知道了以某个点为右下角的最大正方形长度,那我同样就能知道以这个点为右下角的其他可能的正方形长度。所以可以想到求出每个点为右下角的最大正方形长,这就是个dp问题了。对菱形也是同样的思路,处理稍微多了几个判断。

#include<cstdio>
#include<map>
#include<queue>
#include<cstring>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<list>
#include<set>
using namespace std;
const int maxn = 500 + 5;
const int INF = 1000000000;
typedef long long LL;
typedef pair<int, int> P;
#define fi first
#define se second

int dps[maxn][maxn], dpd[maxn][maxn];
char maze[maxn][maxn];

int main(){
    int n;
    while(scanf("%d", &n) != EOF){
        memset(maze, -1, sizeof maze);
        for(int i = 1;i <= n;i++){
            scanf("%s", maze[i]+1);
        }
        memset(dps, 0, sizeof dps);
        memset(dpd, 0, sizeof dpd);
        LL ans = 0;
        for(int i = 1;i <= n;i++){
            for(int j = 1;j <= n;j++){
                if(maze[i][j] == 'x'){
                    dps[i][j] = min(dps[i-1][j], dps[i][j-1]);
                    int len = dps[i][j];
                    if(maze[i-len][j-len]=='x')
                        dps[i][j]++;
                    ans += dps[i][j]-1;

                    len = min(dpd[i-1][j-1], dpd[i-1][j+1]);
                    if(len == 0 || maze[i-1][j] != 'x')
                        dpd[i][j] = 1;
                    else{
                        if(maze[i-len-1][j] == 'x' && maze[i-len][j] == 'x')
                            dpd[i][j] = len+2;
                        else
                            dpd[i][j] = len;
                    }
                    ans += dpd[i][j]/2;
                }
            }
        }

        printf("%lld\n", ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值