實驗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個元素的值。
源代碼:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章