20170816(二叉樹的建樹與遍歷 計算幾何 信心)

心情記錄

放假,去實驗室補題,大學長給了我信心!

每個人都有從弱變強的過程,我只付出了一個月出頭,只是很多人的1/36啊

加油↖(^ω^)↗

知識點補充

手動擴棧

#pragma comment(linker, "/STACK:1024000000,1024000000")

題目

HDU 6127 Hard challenge

題意

平面座標系,給出n個點,保證任意兩點的連線不過原點.
每一個點都有一個權值,兩點之間的線段的權值等於端點權值之積
問如果過原點做一條直線,直線穿過的線段的權值和最大是多少

解決

這道題我們卡住了,想到了要用極角排序來做,也想到了去枚舉每一個經過原點和點的直線,但是思路卡在了”如何表示偏差一點點”上面


        //直線左側的點一定能和直線右側的點連成線段,那麼直線兩端任意兩點權值積的和,就是兩個區間權值和的積
        //好像有點繞╮(╯▽╰)╭...
        /*
            p1         /
                      /   p3            p1(p3+p4)+p2(p3+p4)=(p1+p2)*(p3+p4)
             p2      /
                    /    p4             手動繪圖  ∩_∩)O哈哈哈~
                   /
        */
  1. 容易知道,直線兩端任意兩點權值積的和,就是兩個區間權值和的積(代碼裏面畫了圖(想不到吧^_^))
  2. 首先按照極角對每個點進行排序
  3. 初始直線從y軸開始,把x>=0的點都加到右區間,x<0的點都加到左區間
  4. 直線逆時針旋轉,每旋轉到一個點,把這個點從它原來所在的區間裏面剔除掉,加到另一個去見裏面
  5. 保存最大值
#define rep(i,a,b) for(int i=a;i<(b);++i)
struct point
{
    int x,y,val;
    double angle;
}P[50005];

bool cmp(point p1,point p2)
{
    return p1.angle<p2.angle;
}

int main()
{
    int n,cases;
    long long ans,lsum,rsum;        //lsum和rsum不會爆int但是相乘會爆int
    scanf("%d",&cases);
    while(cases--)
    {
        scanf("%d",&n);
        rep(i,0,n){
            scanf("%d%d%d",&P[i].x,&P[i].y,&P[i].val);
            if(P[i].x==0)           //這裏對x=0進行特判,除數不能爲0
            {
                if(P[i].y>0) P[i].angle=PI/2.0;
                else P[i].angle=-PI/2.0;
            }
            else P[i].angle=atan(P[i].y*1.0/P[i].x);
        }
        //rep(i,0,n) cout<<P[i].angle<<endl;
        sort(P,P+n,cmp);

        ans=1;
        lsum=rsum=0;

        //初始先以y軸對做表面進行劃分
        rep(i,0,n){
            if(P[i].x>=0) rsum+=P[i].val;   //出現在y軸右側(包含y軸)的點全部添加到右區間
            else lsum+=P[i].val;
        }
        //直線左側的點一定能和直線右側的點連成線段,那麼直線兩端任意兩點權值積的和,就是兩個區間權值和的積
        //好像有點繞╮(╯▽╰)╭...
        /*
            p1         /
                      /   p3            p1(p3+p4)+p2(p3+p4)=(p1+p2)*(p3+p4)
             p2      /
                    /    p4             手動繪圖  ∩_∩)O哈哈哈~
                   /
        */
        ans=lsum*rsum;

        rep(i,0,n){            //根據極角排序的順序,遍歷每一個點,然後把這個點從它之前所在的區間裏剔除加到另一個區間
            if(P[i].x>=0)              //原來在右區間,從右區間剔除
            {
                rsum-=P[i].val;
                lsum+=P[i].val;
            }
            else                            //原來在左區間,從左區間剔除
            {
                rsum+=P[i].val;
                lsum-=P[i].val;
            }
            ans=max(ans,lsum*rsum);
        }
        cout<<ans<<endl;
    }
}

UVA_122 Trees on the level

題意

讓我們構建一棵樹,給出每一個節點是從根節點怎麼走才能走到.
比如(11,LL)就是根節點的左子樹的左子節點的位置權值爲11.然後讓給出這棵樹的先序遍歷結果.
如果出現下列情況,輸出”not complete”

  1. 重複賦值
  2. 沒有根節點
  3. 有節點沒有被賦值(子節點有賦值,但是本身卻沒有賦值的情況)
  4. 給出超過一個節點

解決

這個題的輸入比較坑啊,剛上來感覺解決不了…
看了紫書,參考了博客.

解決輸入
  1. 主函數中用一個大循環,一直循環創建一個bool readin()函數
  2. 當程序讀入EOF的時候返回false,主函數退出循環
  3. 當readin中讀入”()”,返回true,主函數繼續循環

C語言字符串的靈活性-可以把任意”指向字符的指針”當做是字符串,從該位置開始,直到字符’\0’

建樹

  1. 創建node結構體,包含指向左兒子和右兒子的指針
  2. 每次從根節點開始走,走到對應位置,對當前位置進行賦值

先序遍歷

先序遍歷=根節點+左兒子的先序+右兒子的先序

  1. 用一個vector來保存遍歷結果
  2. 根節點入隊
  3. 如果左兒子存在,左兒子入隊
  4. 如果右兒子存在,右兒子入隊
#include<bits/stdc++.h>
using namespace std;
#define de(x) cout << #x << "=" << x << endl
#define rep(i,a,b) for(int i=a;i<(b);++i)

struct node
{
    bool have_value;                        //是否已經被賦值
    int v;
    node *left,*right;
    node():have_value(false),left(NULL),right(NULL){}
};
node *root;
node *newnode(){return new node();}         //new函數後面要加個括號
bool gg;

void addnode(int v,char *s)
{
    int len=strlen(s);
    node *u=root;                           //u從根節點開始走,直到目標節點
    rep(i,0,len){
        if(s[i]=='L')
        {
            if(u->left==NULL) u->left=newnode();
            u=u->left;
            continue;
        }
        if(s[i]=='R')
        {
            if(u->right==NULL) u->right=newnode();
            u=u->right;
            continue;
        }
    }
    if(u->have_value){gg=true;return ;}     //如果當前節點已經被賦值,gg
    u->v=v;
    u->have_value=true;                     //標記爲已賦值
}

void delete_tree(node *u)
{
    if(u==NULL) return ;
    delete_tree(u->left);
    delete_tree(u->right);
    delete u;
}

bool readin()
{
    char str[270];
    gg=false;
    while(1)
    {
        if(scanf("%s",str)==EOF) return false;  //程序讀到EOF
        if(!strcmp(str,"()")) break;
        int v;
        //de(str);
        sscanf(&str[1],"%d",&v);                //ssanf的使用要頭文件sstream
        //de(v);
        addnode(v,strchr(str,',')+1);           //strchr()返回字符串從左到右第一個字符‘,’的指針
    }
    return true;
}

vector<int> ans;
bool bfs()
{
    ans.clear();
    queue<node*> Q;
    Q.push(root);
    while(!Q.empty())
    {
        node *u=Q.front();Q.pop();
        if(!u->have_value) {gg=true;return false;}
        ans.push_back(u->v);
        if(u->left!=NULL) Q.push(u->left);
        if(u->right!=NULL) Q.push(u->right);
    }
    return true;
}
int main()
{
    while(1)
    {
        delete_tree(root);
        root=newnode();
        if(!readin()) break;        //程序讀到了EOF
        if(!gg&&bfs())
        {
            for(int i=0;i<ans.size();i++)
                printf("%d%c",ans[i],i+1==ans.size()?'\n':' ');
        }
        else puts("not complete");
    }
}
發佈了54 篇原創文章 · 獲贊 8 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章