正方形UVa201-紫书习题4-2(详细解答)

news/2024/6/15 19:13:22 标签: 数据结构, 动态规划, 算法, acm竞赛

题目:
有n行n列的小黑点,还有m条线段连接其中小黑点。统计这些线段练成了多少个正方形(按边长分别统计),从行上到下编号1~~n,列从左到右1~n,。边用Hij,Vij表示,分别代表(i,j)到(i,j+1)这两点之间的边,和(i,j)到(i+1,j)这两点之间的边。

输入输出:
输入n行n列,在输入m条边,m条边用Hij,Vij表示

题目解析:
这道题就是在n*n个点所构成的正方形,以及它输入的m条边的位置,找出一共有多少个正方形,正方形的长度可以不同,Hij也就是在(i,j)这个点向右侧延申一条边出来,Vij也就是(i,j)向下延申一条边。

解题思路:
对于每一个点(i,j)我们依次遍历,记录每一个点向右,以及向下延申的最大长度,放入数组hExp[i][j],和vExp[i][j]中.
hExp[i][j]=hExp[i][j+1]+1,vExp[i][j]=vExp[i+1][j]+1;
也就是,我们从后向前遍历,把后面点能延伸的最大长度,加上自身长度,即我最大能延申长度。

顺序遍历每一个(i,j),依次判断以(i,j)为左上顶点所有可能的正方形边长为s,其中s为1到min(hExp[i][j],vExp[i][j])也就是向右或向下延申的最小值,我们遍历所有长度,找出所有可能的正方形,那么如何判断能否构成一个正方形呢?

我们计算出(i,j)的左下点向右延申的最大值即hExp[i+s][j],和右上点向下延申的最大值,即vExp[i][j+s],只要满足>=s就可以构成正方形。

图解:
在这里插入图片描述
代码:

#include<bits/stdc++.h>
#define _for(i,a,b) for(int i=a;i<b;i++)
#define _rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=16;
int n,m,vExp[maxn][maxn],hExp[maxn][maxn],H[maxn][maxn],V[maxn][maxn],Squares[maxn];
int main()
{
    char buf[4];
    int x,y;

    for(int t=1; scanf("%d",&n)==1; t++)
    {
        printf("\n******************************************\n\n");
        //初始化数组
        memset(vExp,0,sizeof(vExp)), memset(hExp,0,sizeof(hExp));
        memset(H,0,sizeof(H)), memset(V,0,sizeof(V)), memset(Squares,0,sizeof(Squares));
        scanf("%d",&m);//读入m条边
        _for(i,0,m)
        {
            //确定m条边位置
            scanf("%s%d%d",&buf,&x,&y);
            if(buf[0]=='H')H[x][y]=1;//输入H则H[i][j]=1
            else V[x][y]=1;//输入V则V[i][j]=1
        }
        //求出每一条边最长能延申多长存放hEXP,vEXP中
        for(int i=n; i>=1; i--)
            for(int j=n; j>=1; j--)
            {
                if(H[i][j]) hExp[i][j]=hExp[i][j+1]+1;//当前边加上,它右侧的边向右延申最大长度
                if(V[i][j]) vExp[i][j]=vExp[i+1][j]+1;//同上,只是向下延申
            }

        _rep(i,1,n)_rep(j,1,n){
            int maxS=min(hExp[i][j],vExp[i][j]);//找出该点,能满足最大正方形
            //遍历所有小于maxS的边,防止一个起点,有多个边长的正方形
            _rep(s,1,maxS){
                if(hExp[i+s][j]>=s&&vExp[i][j+s]>=s){//找出左下点向右延申最大值,以及右上点向下延申的最大值,都要满足>=s才能构成正方形
                    Squares[s]++;//当前s长的正方形++
                }
            }
        }
        printf("Problem #%d\n\n",t);//第t次
        bool found=false;
        _rep(i,1,n) if(Squares[i]){
            found=true;
            printf("%d square(s) of size %d\n",Squares[i],i);//打印长度为i的正方形个数
        }
        if(!found) puts("NO completed squares can be found.");

    }
    return 0;
}

解释代码细节:

#define _for(i,a,b) for(int i=a;i<b;i++)
#define _rep(i,a,b) for(int i=a;i<=b;i++)
定义了两个for循环,第一个i从a开始,i<b,i++,第二个只不过i<=b

memset()初始化数组为0

这道题就解释到这里,希望大家多多支持!
一键三连嘻嘻!


http://www.niftyadmin.cn/n/860391.html

相关文章

Java 实现笛卡尔积计算

代码 // 实现思路计算当前第N个List和前面N-1个List的笛卡尔积集合的笛卡尔积集合&#xff08;动态规划&#xff09;public static<T> List<List<T>> cartesianProduct(List<List<T>> data){List<List<T>> res null; // 结果集(当…

Java double转bigDecimal时精度丢失问题

使用new BigDecimal(double val)对doubel进行转换会导致转换后精度丢失 原因 BigDecimal的构造函数public BigDecimal(double val)会损失了double 参数的精度。jdk中已经明确不建议使用new BigDecimal(double value)这种形式的构造函数&#xff0c;而是使用new BigDecimal(St…

集合栈计算机(详细解答)UVa12096

题目: 有一个专门为了集合运算而设计的“集合栈”计算机。该机器有一个初始为空的栈&#xff0c;并且支持以下操作&#xff1a; PUSH&#xff1a;空集“{}”入栈 DUP&#xff1a;把当前栈顶元素复制一份后再入栈 UNION&#xff1a;出栈两个集合&#xff0c;然后把两者的并集入栈…

vue根据权限动态生成路由

vue根据权限动态生成路由 import store from /store // vuex import router from /router // router import axios from ./request // axios // 存放页面信息 const data [// { // 主菜单// path: /okkk, // 页面路径// name: okkk, // 名称// component: () > impo…

团体队列(模拟)

题目: 团体队列题目 思路: 这是一道模拟题,通过map,和两个queue完成,具体细节大家看代码注释,找清楚之间的关系就好。 #include <bits/stdc.h> using namespace std; const int maxt100010;//最多团队数int main() {int t,kcase0;//读入t个团while(scanf("%d"…

丑数-优先队列(详细解答)

题目: 丑数是一些因子只有2,3,5的数。数列1,2,3,4,5,6,8,9,10,12,15……写出了从小到大的前11个丑数&#xff0c;1属于丑数。现在请你编写程序&#xff0c;找出第1500个丑数是什么。 输出&#xff1a;The 1500’th ugly number is <…>.&#xff08;<…>为你找到的…

Unix Is命令(UVa 400)详细解答

题目: 输入正整数n 以及n 个文件名&#xff0c;排序后按列优先的方式左对齐输出。假设最长文件名有M 字符&#xff0c;则最右边有M 字符&#xff0c;其他列都是M2 字符。 题目分析: 有n个文件名,其中最长的文件名有M个字符,一下面输入为例,最长的是Mr._French(共有10个字符),然…

超级楼梯(递推)

题目: 有一楼梯共M级&#xff0c;刚开始时你在第一级&#xff0c;若每次只能跨上一级或二级&#xff0c;要走上第M级&#xff0c;共有多少种走法&#xff1f; 输入: 输入数据首先包含一个整数N&#xff0c;表示测试实例的个数&#xff0c;然后是N行数据&#xff0c;每行包含一…