首页 > 技术文章 > 分冶法解决大整数相乘 最近对问题

someonezero 2020-05-09 21:34 原文

1.大整数相乘

问题描述:

 

 

 所以需要用字符串的方式进行存储,于是衍生了大整数相乘的问题

两位数的示例:

例如:11*11=(1*10^1+1*10^0)*(1*10^1+1*10^0)=1*10^2+(1+1)*10^1+1*10^0

输入数据:11 11

输出数据:121

代码参考网址:https://www.bbsmax.com/A/VGzloP7ldb/

//date:2020.5.9
#include<bits/stdc++.h>
using namespace std;

const int maxn = 100;
void reverse(char a[])
{
    int len = strlen(a);
    for(int i = 0 ; i < len / 2; i++)
    {
        int temp = a[i];
        a[i] = a[len - i - 1];
        a[len - i -1] = temp;
    }
}
int main()
{
    char a[maxn],b[maxn];
    int t[100] = {0};
    printf("Please enter 2 numbers: ");
    scanf("%s%s",a,b);
    reverse(a);
    reverse(b);
    if(strcmp(a,"0")==0||strcmp(b,"0")==0)
        cout<<"0"<<endl;
    else
    {
        int i,j;
        for(i = 0; i <strlen(b); i++)
        {
            int cnt = 0;
            for(j = 0; j < strlen(a); j++)
            {
                int temp = (b[i] - '0') * (a[j] - '0');//表示结果
                int tt= t[i+j] + temp + cnt;//表示与原来计算出对应级数相加
                t[j+i] = tt % 10;
                cnt = tt / 10;//cnt表示是否有进位
            }
            while(cnt != 0)
            {
                t[j+i] = cnt % 10;
                cnt = cnt / 10;
                j++;//此处j++用于结果输出的时候i+j-2对应
            }
        }
        for(int k = i + j - 2; k >= 0; k--)//j比原来的位数多1
        {
            cout<<t[k];
        }
    }
    return 0;
}

代码的巧妙之处在于,i+j的结果就是10的几次的结果,所以十分巧妙,可以根据调试代码和阅读注释看懂代码,找了很久才找到这个好懂的代码

2.分冶法解决最进对问题

参照网址:https://www.cnblogs.com/zyxStar/p/4591897.html

 

 最简单的就是用蛮力法解决

此处用的分冶法来解决(用的是递归,不断划分)

先排序,然后不断平分,但是要比较两个区域相邻的最近对,所以问题变成求 左边 右边 相邻区域中间 这三个区域的最近对

 

 中间区域选的区间d大小 d=min(d1,d2)

输入:

1 1

2 2

3 3

0

输出:

1.41

//date:2020.5.9
#include<bits/stdc++.h>
using namespace std;
const double inf = 1e20;
const int maxn = 100005;

struct Point
{
    double x, y;
} point[maxn];

int n, mpt[maxn];

//以x为基准排序
bool cmpxy(const Point& a, const Point& b)
{
    if (a.x != b.x)
        return a.x < b.x;
    return a.y < b.y;
}

bool cmpy(const int& a, const int& b)
{
    return point[a].y < point[b].y;
}

double min(double a, double b)
{
    return a < b ? a : b;
}

double dis(int i, int j)
{
    return sqrt((point[i].x - point[j].x)*(point[i].x - point[j].x) + (point[i].y - point[j].y)*(point[i].y - point[j].y));
}

double Closest_Pair(int left, int right)
{
    double d = inf;
    if (left == right)
        return d;
    if (left + 1 == right)
        return dis(left, right);
    int mid = (left + right) >> 1;
    double d1 = Closest_Pair(left, mid);
    double d2 = Closest_Pair(mid + 1, right);
    d = min(d1, d2);
    int i, j, k = 0;//左右两边的都已经找完了
    //分离出宽度为d的区间,找中间d最小的距离
    for (i = left; i <= right; i++)
    {
        if (fabs(point[mid].x - point[i].x) <= d)
            mpt[k++] = i;
    }
    sort(mpt, mpt + k, cmpy);
    //线性扫描
    for (i = 0; i < k; i++)
    {
        for (j = i + 1; j < k && point[mpt[j]].y - point[mpt[i]].y<d; j++)
        {
            double d3 = dis(mpt[i], mpt[j]);
            if (d > d3)
                d = d3;
        }
    }
    return d;
}

int main()
{
    while (~scanf("%d", &n) && n)
    {
        for (int i = 0; i < n; i++)
            scanf("%lf %lf", &point[i].x, &point[i].y);
        sort(point, point + n, cmpxy);
        printf("%.2lf\n", Closest_Pair(0, n - 1) );
    }
    return 0;
}

核心就是划分再划分,直到最后划分的区域中只有一个或者两个点.这样,该区域的最近点对距离就是无穷大或者该两点的距离。这也是递归终止的条件。

还有一个知识点是sort中最后一个参数的使用,值得思考

推荐阅读