2017年聯發科編程比賽-傑克船長的煩惱

首先看題目要求:

傑克船長的煩惱

傑克船長這次運氣不錯,搶到了一大堆金幣。但他馬上又開始發愁了, 因爲如何給大家分金幣,一直都是件不容易的事,每次傑克船長都要頭疼好幾天。

關於分金幣,海盜的行規是這樣的:

  1. 每次行動,船長會根據各個海盜的表現記功,事後論功行賞,給大家分金幣。

  2. 分戰利品的時候,海盜們會隨意的站成一排,船長給每個人發一袋金幣。袋子裏的金幣數目有多有少,但船長保證每個海盜至少會分到一枚金幣。

  3. 拿到金幣後,相鄰的兩個海盜會互相比較。如果其中一個功勞高些,那他的金幣必須多一些,如果兩個人分數一樣,他們的金幣必須一樣。否則,海盜們就覺得不公平,要鬧事,甚至造反。

怎麼樣才能用最少的金幣讓大家都滿意呢? 領導這幫海盜可不輕鬆。

聽說這次比賽中有一位將來要成爲海賊王的男人,傑克船長相信他一定能解決這個麻煩。

輸入說明

在程序當前目錄下存在execute.stdin文件,程序從execute.stdin中取得輸入數據。

execute.stdin中存放着N(N<100)個十進制正整數,數字之間用空格格開。

每個數字都代表某個海盜的功勞,值範圍爲(1, 100)。

輸出說明

輸出一個正整數,代表讓所有海盜都滿意的最少的金幣數。

示例

execute.stdin內容: 1 3 3 2

預期輸出:6

說明:符合要求的金幣分法是 1 2 2 1

題目解讀:就是有一串數,給這串數種的每個數附一個權,權儘量小,但是兩個相鄰的數,本身大的數,其權必大於其相鄰的小的數。

思路,採用排序樹的思路,不過不是二叉樹,每個節點只有左子樹或者只有右子樹,左子樹<父節點,右子樹>=父節點,父節點的權值等於左子樹深度,或者等於前一個權加1。

圖中主要介紹了這種思想,注意右側樹葉,沒有左孩子也沒有右孩子,要麼等於父節點,要麼等於父節點+1。

最複雜的是中間的右分支,相等的情況都出現這裏。儘量向父節點靠,即如果有一個節點的值等於父節點,那麼他的權應該儘量等於父節點,但是如果這個節點是右側的轉折點,那麼父節點要想該節點靠,即權等於該節點。

 

算法如下:

#include<iostream>
#include<vector>
#include<fstream>

using namespace std;
//基於二叉排序樹
typedef struct SortTree
{
    SortTree* lchild;
    SortTree* rchild;
    int val;
    SortTree(int x)
    {
        val = x;
    }
}*STree;

STree CreateSTree(vector<int>vec)
{
    STree tree = new SortTree(vec[0]);
    tree->lchild = NULL;
    tree->rchild = NULL;
    STree  pTree = tree;
    for (int i = 1; i < vec.size(); i++)
    {
        
        if (vec[i] < vec[i - 1])
        {
            pTree->lchild = new SortTree(vec[i]);
            pTree->rchild = NULL;
            pTree = pTree->lchild;
        }
        else
            if (vec[i] >= vec[i - 1])//相等的情況放在右子樹,因爲我們用左子樹深度判定金幣
            {
                pTree->rchild = new SortTree(vec[i]);
                pTree->lchild = NULL;
                pTree = pTree->rchild;
            }
    }
    pTree->lchild = NULL;
    pTree->rchild = NULL;
    return tree;
}

void  TreePrint(STree tree)
{
    if(tree)
    {
        
            cout << tree->val << " ";
            TreePrint(tree->lchild);
            TreePrint(tree->rchild);
        
    }
}
//右子樹比左子樹大1,左子樹深度+1是根的金幣
//我們的數據要麼有左子樹要麼有右子樹,不可能同時有左右子樹
int deep(STree  tree)
{
    int num = 0;
    STree deepTree = tree;
    while (deepTree->lchild!=NULL)
    {
        num++;
        deepTree = deepTree->lchild;
    }
    num++;
    return num;//左子樹深度
}

bool   parent_has_lchild(STree  tree ,int  i)//搜索i節點的父節點是否有左子樹
{
    for (int j = 0; j < i-1; j++)
    {
        if (tree->lchild)
        {
            tree = tree->lchild;
        }
        else
        if (tree->rchild)
        {
            tree = tree->rchild;
        }
    }
    if (tree->lchild)
    {
        return true;
    }
    else
        return false;
}
bool   father_equal_child(STree tree, int i)
{
    for (int j = 0; j < i - 1; j++)
    {
        if (tree->lchild)
            tree = tree->lchild;
        else
            if (tree->rchild)
                tree = tree->rchild;
    }
    if (tree->lchild)
    {
        if (tree->val == tree->lchild->val)
            return true;
    }
    else
        if (tree->rchild)
        {
            if (tree->val == tree->rchild->val)
            {
                return true;
            }
        }
    return false;
    
}

vector<int>deepjihe(STree  tree,int length)
{
    vector<int>vec;
    STree m_deep = tree;
    for (int i = 0; i < length; i++)
    {
        if (m_deep->lchild  && m_deep==tree)//頭節點有左孩子
        {
                //有左子樹
                int  ldeep = deep(m_deep);
                vec.push_back(ldeep);
                m_deep = m_deep->lchild;
                //左子樹上的值,以此賦值,不能放在後面處理
        }
        else
            if (m_deep->lchild && m_deep != tree && !parent_has_lchild(tree,i))//不是頭節點,有左孩子,要判斷左孩子深度與父節點的大小,如果大,就=深度,否則,=父節點+1
            {
                int ldeep = deep(m_deep);//取深度
                if (ldeep >= vec[i - 1])
                {
                    vec.push_back(ldeep);
                    m_deep = m_deep->lchild;
                }
                else
                {
                    vec.push_back(vec[i - 1] + 1);
                    m_deep = m_deep->lchild;
                }
            }
            else
                if (m_deep->lchild && m_deep != tree && parent_has_lchild(tree, i))
                {
                    int ldeep = deep(m_deep);//取深度
                    vec.push_back(ldeep);
                    m_deep = m_deep->lchild;
                }
        else
        if(m_deep->rchild)
        {
            if (m_deep == tree)//頭節點
            {
                vec.push_back(1);
                m_deep = m_deep->rchild;
            }

            else
            {
                if (parent_has_lchild(tree, i))//判斷i節點的父節點是否有左孩子,有的話,i節點對應的是1,不然,前一個值+1
                {
                    vec.push_back(1);
                    m_deep = m_deep->rchild;
                }
                else
                    if(!parent_has_lchild(tree, i))
                    {
                        vec.push_back(vec[i - 1] + 1);
                        m_deep = m_deep->rchild;

                    }
            }
        }
        else
            if (m_deep->rchild == NULL &&  m_deep->lchild == NULL  && parent_has_lchild(tree,i))//父節點有左孩子
            {
                vec.push_back(1);
            }
            else
                if (m_deep->rchild == NULL &&  m_deep->lchild == NULL  && !parent_has_lchild(tree, i))
                {
                    if (father_equal_child(tree,i))//判斷父節點的val與該節點的大小
                        vec.push_back(vec[i - 1]);
                    else
                        vec.push_back(vec[i - 1] + 1);
                }


    }
    return vec;
}
//判斷當前節點是否有左孩子
bool   cur_has_lchild(STree tree, int i)
{
    for (int j = 0; j < i; j++)
    {
        if (tree->lchild)
        {
            tree = tree->lchild;
        }
        else
            if (tree->rchild)
            {
                tree = tree->rchild;
            }
    }
    if (tree->lchild)
    {
        return true;
    }
    else
        if (tree->rchild)
        {
            return false;
        }
    return false;
}

bool  is_right_turn(STree tree, int i)
{
    if (!parent_has_lchild(tree, i) && cur_has_lchild(tree, i))
    {
        return true;
    }
    else
        return false;
}
bool  is_left_turn(STree tree, int i)
{
    if (parent_has_lchild(tree, i) && !cur_has_lchild(tree, i))
    {
        return true;
    }
    else
        return  false;
}

//這個函數的作用是修正數組,從根節點依次判斷,如果是轉折點(父節點有右孩子,自己有左孩子),
//那麼都得向這個方向靠攏,我們的樹把相等的放在了右孩子上了
vector<int>hasEqual(STree tree, vector<int>vec,vector<int>vec1)
{
    vector<int>vec2;
    vec2 = vec1;
    for (int i = 1; i < vec.size(); i++)
    {

        if (father_equal_child(tree,i))//父節點與子節點相等
        {
            if (is_right_turn(tree, i) && !is_left_turn(tree, i - 1))//當前節點是右轉折點,前一個節點不是左轉折點
            {
                vec2[i - 1] = vec2[i];
                
            }
            else
                if (!is_right_turn(tree, i) && is_left_turn(tree, i - 1))//當前節點不是右轉折點,前一個節點是左轉折點
                {
                    vec2[i] = vec2[i - 1];
                    
                }
                else
                {
                    vec2[i] = vec2[i - 1];
                    
                }
        }
    }
    return  vec2;
}

int sum(vector<int>vec)
{
    int sum = 0;
    for (int i = 0; i < vec.size(); i++)
    {
        sum = sum + vec[i];
    }
    return sum;
}


int main()
{
    ifstream  ifs;
    ifs.open("execute.stdin");
    int num = 0;
    vector<int>vec;
    while (ifs >> num)
    {
        vec.push_back(num);
    }
    ifs.close();


    STree tree = CreateSTree(vec);
    
    vector<int>vec1;
    vec1 = deepjihe(tree, vec.size());


    vector<int>vec2;
    vec2 = hasEqual(tree,vec,vec1);


    int sump = 0;
    sump = sum(vec2);
    cout << sump << endl;


    return 0;
}

 

 

 

PS:本人是算法小白,研究方向也不再此,只是想出來一個小想法並且進行了實現,有不好之處請指教。

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