B00015 平方矩阵问题

给定n,m,min和max,求所有的<i,j>,满足0<=i<=n,0<=j<=m并且min<=i*j<=max。

要求:不得使用暴力法,算法复杂度要求O(n,m)<nlogm并且O(n,m)<mlogn。

提示:

1.设有k和l,若满足k*l<min,对于i<=k且j<=l,则<i,j>是不满足条件的;若k*l>max,对于i>=k且j>=l,则<i,j>是不满足条件的。

2.可以考虑用三分法。

3.需要考虑n和m比较小的情形,例如0,1,2,也许需要做特殊的处理。

样例数据如下:

输入:n,m,min和max分别为10,10,31,41

结果:

<4 8>
<4 9>
<4 10>
<5 7>
<5 8>
<6 6>
<7 5>
<8 4>
<8 5>
<9 4>
<10 4>


暴力法程序如下:

/* B00015 平方矩阵问题(暴力法) */

#include <iostream>

using namespace std;

int main()
{
    int n, m, mins, maxs;

 scanf("%d%d%d%d", &n, &m, &mins, &maxs);

    for(int i=0; i<=n; i++)
        for(int j=0; j<=m; j++) {
            if(mins <= i * j && i * j <= maxs)
                printf("<%d %d>\n", i, j);
        }

    return 0;
}


运行结果(输入与输出):

10 10 31 41
<4 8>
<4 9>
<4 10>
<5 7>
<5 8>
<6 6>
<7 5>
<8 4>
<8 5>
<9 4>
<10 4>


根据网友提供的程序改进后的程序:

/* B00015 平方矩阵问题(二分法) */

#include <iostream>
#include <stdio.h>

using namespace std;

int b_search_max(int row, int left, int right , int maxs)
{
    int mid;
    while(left <= right) {
        mid = (left + right) / 2;
        if(row * mid > maxs)
            right = mid - 1;
        else if(row * mid < maxs)
            left = mid + 1;
        else { // ==
            left = mid;
            break;
        }
    }
    return right;
}

int b_search_min(int row, int left, int right , int mins)
{
    int mid;
    while(left <= right) {
        mid = (left + right) / 2;
        if(row * mid < mins)
            left = mid + 1;
        else if(row * mid > mins)
            right = mid - 1;
        else { // ==
            left = mid;
            break;
        }
    }
    return left;
}

int main()
{
    int n, m, mins, maxs;
    int bot, top;

    scanf("%d%d%d%d", &n, &m, &mins, &maxs);

    for(int i=0; i<=n; i++) {
        top = b_search_max(i, 0, m, maxs);
        bot = b_search_min(i, 0, top, mins);
        for(int j = bot; j <= top; j++)
            printf("<%d %d>\n", i, j);
    }

    return 0;
}

运行结果(输入与输出)之一:

10 10 31 41
<4 8>
<4 9>
<4 10>
<5 7>
<5 8>
<6 6>
<7 5>
<8 4>
<8 5>
<9 4>
<10 4>


运行结果(输入与输出)之二:

15 15 31 41
<3 11>
<3 12>
<3 13>
<4 8>
<4 9>
<4 10>
<5 7>
<5 8>
<6 6>
<7 5>
<8 4>
<8 5>
<9 4>
<10 4>
<11 3>
<12 3>
<13 3>


进一步改进后的程序:

/* B00015 平方矩阵问题(综合二分法) */

#include <iostream>
#include <stdio.h>

using namespace std;

int b_search_max(int row, int left, int right , int maxs)
{
    int mid;
    while(left <= right) {
        mid = (left + right) / 2;
        if(row * mid > maxs)
            right = mid - 1;
        else if(row * mid < maxs)
            left = mid + 1;
        else { // ==
            left = mid;
            break;
        }
    }
    return right;
}

int b_search_min(int row, int left, int right , int mins)
{
    int mid;
    while(left <= right) {
        mid = (left + right) / 2;
        if(row * mid < mins)
            left = mid + 1;
        else if(row * mid > mins)
            right = mid - 1;
        else { // ==
            left = mid;
            break;
        }
    }
    return left;
}

int main()
{
    int n, m, mins, maxs;
    int bot, top;

    scanf("%d%d%d%d", &n, &m, &mins, &maxs);

    int minrow = b_search_min(m, 0, n, mins);
    int maxcol = b_search_max(minrow, 0, m, maxs);
    int mincol = b_search_min(n, 0, maxcol, mins);
    int maxrow = b_search_max(mincol, minrow, n, maxs);

    for(int i=minrow; i<=maxrow; i++) {
        top = b_search_max(i, mincol, maxcol, maxs);
        bot = b_search_min(i, mincol, top, mins);
        for(int j = bot; j <= top; j++)
            printf("<%d %d>\n", i, j);
    }

    return 0;
}


运行结果(输入与输出)之一:

10 10 31 41
<4 8>
<4 9>
<4 10>
<5 7>
<5 8>
<6 6>
<7 5>
<8 4>
<8 5>
<9 4>
<10 4>


运行结果(输入与输出)之二:

15 15 31 41
<3 11>
<3 12>
<3 13>
<4 8>
<4 9>
<4 10>
<5 7>
<5 8>
<6 6>
<7 5>
<8 4>
<8 5>
<9 4>
<10 4>
<11 3>
<12 3>
<13 3>

  



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值