实验4 分治算法实验二

OJ练习
1. 空心三角形:http://acm.hdu.edu.cn/showproblem.php?pid=2091
2. 整除的尾数:http://acm.hdu.edu.cn/showproblem.php?pid=2099
3. 小明A+B:http://acm.hdu.edu.cn/showproblem.php?pid=2096
4. 剪花布条:http://acm.hdu.edu.cn/showproblem.php?pid=2087
5. 算菜价:http://acm.hdu.edu.cn/showproblem.php?pid=2090
6. The Triangle: http://poj.org/problem?id=1163
7*. 免费馅饼:http://acm.hdu.edu.cn/showproblem.php?pid=1176
8*. Function Run Fun: http://poj.org/problem?id=1579

实验内容
1. 随机化快速排序。使用Java或C++中内置的随机函数实现随机化快速排序,在数组中随机选择一个元素作为分区的主元(Pivot)。【输入:一个一维整型数组;输出:随机化快速排序之后的一维整型数组】
源代码:

#include <bits/stdc++.h>

using namespace std;

const int N = 500000;
int a[N];

int Rand(int a, int b)
{
    return (rand()%(b-a)+a+1);
}

void QuickSort(int a[], int left, int right)
{
    if(left >= right) return ;
    int i = left, j = right;
    int b = Rand(i,j);
    int k = a[b];
    while(i < j){
        while(a[i] < k) i++;
        while(a[j] > k) j--;
        if(i <= j){
            swap(a[i],a[j]);
            i++;
            j--;
        }
    }
    QuickSort(a,left,j);
    QuickSort(a,i,right);
}

int main()
{
    int n;
    cin>>n;
    for(int i=0; i<n; i++){
        cin>>a[i];
    }
    QuickSort(a,0,n-1);
    for(int i=0; i<n; i++){
        cout<<a[i]<<" ";
    }
    cout<<endl;
    return 0;
}
  1. 第k大元素问题。输入n个整数和一个正整数k(1<=k<=n),输出这些整数从大到小排序后的第k个。(要求时间复杂度为O(n),需使用随机化分区)
    源代码:
#include <bits/stdc++.h>

using namespace std;

const int N = 500000;
int a[N];

int quick_select(int a[], int l, int r, int k) {
    int p = rand() % (r - l + 1) + l;
    int x = a[p];
    swap(a[p],a[r]);
    int i = l, j = r;
    while(i < j) {
        while(i < j && a[i] < x) i++;
        if(i < j)
            a[j--] = a[i];
        while(i < j && a[j] > x) j--;
        if(i < j)
            a[i++] = a[j];
    }
    a[i] = x;
    p = i;
    if(i - l + 1 == k) return a[i];
    if(i - l + 1 < k) return quick_select(a, i + 1, r, k - (i - l + 1));
    else return quick_select(a, l, i - 1, k);
}

int main()
{
    int n, k;
    cin >> n >> k;
    for(int i=0; i<n; i++){
        cin >> a[i];
    }
    printf("%d\n", quick_select(a, 0, n-1, k));
    return 0;
}

  1. 设计一个分治算法,求一个数组中的最大数和最小数。【提示:可以将数组中的数据分为两组,分别求每一组的最大数和最小数,然后再比较这两组数的最大数和最小数。】
    源代码:
#include <bits/stdc++.h>

using namespace std;

const int N = 500000;
int a[N];

void get(int left, int right, int &Max, int &Min)
{
    if(left == right){
        Max = a[left];
        Min = a[left];
        return ;
    }
    else if(left + 1 == right){
        Max = a[left] > a[right] ? a[left] : a[right];
        Min = a[left] > a[right] ? a[right] : a[left];
        return ;
    }
    else{
        int mid = (left + right) / 2;
        int lMax, lMin, rMax, rMin;
        get(left, mid, lMax, lMin);
        get(mid, right, rMax, rMin);
        Max = max(lMax,rMax);
        Min = min(lMin,rMin);
    }
}

int main()
{
    int n, Max, Min;
    cin >> n;
    for(int i=0; i<n; i++){
        cin >> a[i];
    }
    get(0,n-1,Max,Min);
    printf("Max = %d Min = %d\n", Max, Min);
    return 0;
}
  1. 伪币识别问题。一个袋子中装有256枚金币,其中有一枚是伪币,且已知伪币比真的金币要轻。现在给你一架天平,如何快速找出那枚伪币?使用分治策略来对该问题进行求解,设计并实现相应的分治算法。
    源代码:
#include <bits/stdc++.h>

using namespace std;

const int N = 500000;
int a[N];
int get(int a[], int left, int right)
{
    int ans;

    if(left + 1 == right){
        if(a[left] < a[right])
            return left;
        if(a[left] > a[right])
            return right;
    }
    if((right - left + 1) % 2 == 0){
        int mid = (left + right) / 2;
        int sum1 = 0, sum2 = 0;
        for(int i=left; i<mid+1; i++)
            sum1 += a[i];

        for(int j=mid+1; j<right+1; j++)
            sum2 += a[j];

        if(sum1 < sum2){
            return get(a,left,mid);
        }
        else{
            return get(a,mid+1,right);
        }
    }
    if((right - left + 1) % 2 == 1){
        int mid = (left + right) / 2;
        int sum3 = 0, sum4 = 0;
        for(int i=left; i<mid; i++)
            sum3 += a[i];

        for(int j=mid+1; j<right+1; j++)
            sum4 += a[j];

        if(sum3 < sum4){
            return get(a,left,mid-1);
        }
        if(sum3 > sum4){
            return get(a,mid+1,right);
        }
        if(sum3 == sum4)
            return mid;

    }
    return -1;
}
int main()
{
    int n;
    cin >> n;
    for(int i=0; i<n; i++){
        cin >> a[i];
    }
    printf("%d\n", get(a,0,n-1)+1);
    return 0;
}
  1. 数字三角形。如下图所示的数字三角形,从三角形的顶部到底部有很多条不同的路径。对于每条路径,把路径上面的数加起来可以得到一个和,和最大的路径称为最佳路径。编写一个程序求出最佳路径上的数字之和。【注意:路径上的每一步只能从一个数走到下一层上和它最近的左边的数或者右边的数。】
    7
    3 8
    8 1 2
    2 7 4 4
    4 5 2 6 5
    源代码:
#include <bits/stdc++.h>

using namespace std;

const int N = 105;
int a[N][N];
int *dp;
int main()
{
    int n;
    cin >> n;
    for(int i=1; i<=n; i++)
        for(int j=1; j<=i; j++)
            cin >> a[i][j];
    dp = a[n];
    for(int i=n-1; i>=1; i--)
    {
        for(int j=1; j<=n; j++)
        {
            dp[j] = max(dp[j], dp[j+1]) + a[i][j];
        }
    }
    cout << dp[1]<< endl;
    return 0;
}

6*. 众数问题。给定含有n个元素的多重集合S,每个元素在S中出现的次数称为该元素的重数。多重集S中重数最大的元素称为众数。例如:S = {1,2,2,2,3,5}。该多重集S的众数是2,其重数为3。给定一个一维整型数组,计算它的众数及其重数。
源代码:

#include <bits/stdc++.h>

using namespace std;

const int N = 100005;
int n,x;
int a[N];
map<int,int> m;
int main()
{
    int Max = 0, ans;
    cin >> n;
    for(int i=0; i<n; i++)
    {
        cin >> x;
        m[x]++;
    }
    map<int,int>::iterator it = m.begin();
    for(; it!=m.end(); it++){
        if(it->second > Max){
            Max = it->second;
            ans = it->first;
        }
    }
    printf("%d %d\n",ans,Max);
    return 0;
}
7*. 编写一个程序实现如下功能:

有两个序列a和b,它们的长度分别为n和m,那么将两个序列中的元素对应相乘后得到的n*m 个元素从大到小排列后的第 k个元素是什么?输出第k个元素的值。
源代码:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值