周學習總結

周學習總結

目錄:

第一個ACMer周,第一次沒日沒夜地刷水題,不知道爲什麼,睡眠明顯減少了,倒不是晚上睡不着,而是早晨很早就起牀,說白了,好像是沒有安全感,不謙虛地說:稍微有一點危機感。

學校的網絡中心招聘,我報了名,倒不是想搞網絡,主要是想讓他們給我提供一個方便的學習環境,但是根據朋友說的我發現我的想法好幼稚,呵呵。

這周大多數做的是水題,第一週嘛,但是也稍微做了幾個有技術含量的,多虧了強哥的指點,在這裏謝謝強哥了!但是強哥說的一點我沒有做到,不搜解題報告。有幾個題我實在沒有想法,所以就Google了一下,但是後來我自己寫了這些題目的變形題,保證不是特殊情況一定不搜!

這周把二叉樹的幾種遍歷寫了20遍,但是還不能做到關顯示器就敲出來,繼續努力吧。

令我欣慰的是,自從我統計以來代碼超過了1W,像這個速度,用不了一年就突破10W了。。。。。。

最近做題喜歡用C++,不知道C++裏可不可以用scanfprintf,反正好的編程習慣是肯定不允許這樣做的,但是scanfprintf確實可以讓程序效率變得高的多。這個問題我再考慮考慮吧。

下邊是我這周做的一部分題,附帶很詳細的分析過程。

1.POJ 2255 Tree Recovery

這個題是我今天早晨做出來的,因此印象挺深。

題意是根據先序和中序遍歷的結果來建立二叉樹,然後後序輸出,這就要求我們必須對二叉樹的遍歷很精通(絕對不能僅僅停留在理解的層面)。

首先承認,在做這個題之前我掃了一眼解題報告,僅僅是掃了一眼,我獲得的信息是這個函數的兩個參數,和遞歸的思想,就沒有其它的了。

遞歸,就應該這樣:

二叉樹的根節點是很好建立的,直接前序遍歷的第一個就是,然後就遞歸地遍歷左子樹和右子樹,前序遍歷從第二個開始就是左子樹了,中序遍歷從開始就是左子樹,所以也就得出答案了。

剩下的右子樹也是相同的思路。

奉上代碼:

//===================================

//描述:POJ 2255 Tree Recovery

//作者:Kunsa

//創建日期:2010.5.15

//狀態:已完成

//修改:

//===================================

#include<iostream>

#include<string>

struct ChainBinTree

{

char data;

ChainBinTree *left;

ChainBinTree *right;

};

ChainBinTree *Create(const string &pre,const string &in)

{

ChainBinTree *root=NULL;

if(pre.length()>0)

{

root=new ChainBinTree;

//先序遍歷時訪問的第一個節點就是根節點,因此直接賦值就OK 

root->data=pre[0];

//index的作用在下邊兩個遞歸函數中體現

//index的最終含義其實是左子樹的節點數 

int index=in.find(root->data); 

//前序遍歷時左子樹是從第二個開始遍歷的

//中序遍歷時左子樹是從第一個開始遍歷的 

root->left=Create(pre.substr(1,index),in.substr(0,index));

//index+1都是將根節點和左子樹遍歷結束後的節點索引 

root->right=Create(pre.substr(index+1),in.substr(index+1));

}

return root;

}

void PostOrder(ChainBinTree *bt)

{

ChainBinTree *stack[100];

ChainBinTree *pre=NULL;

int top=-1;

while(bt||top>-1)

{

while(bt)

{

stack[++top]=bt;

bt=bt->left;

}

bt=stack[top];

if(bt->right==NULL||pre==bt->right)

{

pre=stack[top--];

cout<<pre->data;

bt=NULL;

}

else

{

bt=bt->right;

}

}

}

int main()

{

ChainBinTree *bt=NULL;

string pre;

string in;

cin>>pre;

cin>>in;

bt=Create(pre,in);

PostOrder(bt);

cout<<endl;

return 0;

}

註釋寫的很清楚,就不多說了,主要是想把這個改一下,請看下邊的代碼,註釋寫的也很清楚了

//===================================

//描述:後序中序輸入,前序輸出 

//作者:Kunsa

//創建日期:2010.5.15

//狀態:已完成

//修改:

//===================================

#include<iostream>

#include<string>

using namespace std;

struct ChainBinTree

{

char data;

struct ChainBinTree *left;

struct ChainBinTree *right;

};

ChainBinTree *Create(const string &postOrder,const string &inOrder)

{

ChainBinTree *root=NULL;

//最主要的是先找到根節點的值,後序遍歷的話最後一個就是根節點了

int length;

int index;

if((length=postOrder.length())>0)

{

root=new ChainBinTree;

root->data=postOrder[length-1];//根節點賦值

index=inOrder.find(root->data);//index爲左子樹的節點數

//建立左子樹,由於先序和後序遍歷都是先遍歷左子樹,故這兩個的substr

        //參數是相同的

root->left=Create(postOrder.substr(0,index),inOrder.substr(0,index));

        //接下來的遍歷就不同了,後序遍歷需要舍掉最後一個值(根節點)

        //中序遍歷需要舍掉中間的那個值

root->right=Create(postOrder.substr(index,length-index-1),inOrder.substr(index+1));

}

return root;

}

void PreOrder(ChainBinTree *bt)

{

ChainBinTree *stack[100];

int top=-1;

if(bt)

{

stack[++top]=bt;

}

while(top>-1)

{

bt=stack[top--];

cout<<bt->data;

if(bt->right)

{

stack[++top]=bt->right;

}

if(bt->left)

{

stack[++top]=bt->left;

}

}

}

int main()

{

ChainBinTree *bt=NULL;

string post;

string in;

// cin>>post;  爲了測試方便,把輸入的環節去掉了,需要的話可以自己加上

// cin>>in;

post="DBEFCA";

in="DBAECF";

bt=Create(post,in);

PreOrder(bt);

cout<<endl;

return 0;

}

//===================================

//描述:前序後序輸入,中序輸出 

//作者:Kunsa

//創建日期:2010.5.15

//狀態:已完成

//修改:

//===================================

#include<iostream>

#include<string>

using namespace std;

struct ChainBinTree

{

char data;

ChainBinTree *left;

ChainBinTree *right;

};

ChainBinTree *Create(const string &pre,const string &post)

{

int index;

ChainBinTree *root=NULL;

if(pre.length()>0)

{

root=new ChainBinTree;

root->data=pre[0];

index=post.find(pre[1])+1;//左子樹的節點數 

root->left=Create(pre.substr(1,index),post.substr(0,index));

root->right=Create(pre.substr(index+1),post.substr(index,pre.length()-index-1));

}

return root;

}

void InOrder(ChainBinTree *bt)

{

ChainBinTree *stack[100];

int top=-1;

while(bt||top>-1)

{

while(bt)

{

stack[++top]=bt;

bt=bt->left;

}

bt=stack[top--];

cout<<bt->data;

bt=bt->right;

}

}

int main()

{

string s1="ABDCEF";

string s2="DBEFCA";

ChainBinTree *bt=Create(s1,s2);

InOrder(bt);

cout<<endl;

return 0;

}

2.POJ 3750 小孩報數問題

很明顯,這是個約瑟夫數列問題,之前做過一個類似的,因此這道題解起來並沒有費多大勁。但是後來從網上看好像可以不用單循環鏈表的方法,詳細的沒有看,今天晚上回去一定要搜一搜,以不變應萬變。

廢話不說,奉上代碼。

#include<stdio.h>

#include<stdlib.h>

#include<string.h>

typedef struct ListNode

{

char data[15];

struct ListNode *next;

}ListNode,*LinkList;

int _tmain(int argc, _TCHAR* argv[])

{

int n,childNum;

int W,S,count;

ListNode *head,*tail,*p;

head=tail=p=NULL;

scanf("%d",&childNum);

for(n=0;n<childNum;n++)

{

if(p=(ListNode*)malloc(sizeof(ListNode)))

{

scanf("%s",&p->data);

if(head==NULL)

{

head=p;

}

else

{

tail->next=p;

}

tail=p;

tail->next=head;

}

else

{

printf("OverFlow!");

}

}

scanf("%d,%d",&W,&S);

p=head;

for(n=0;n<W-2;n++)//找到第W-2

{

p=p->next;

}

count=0;

while(p!=p->next)

{

if(count==S-1)

{

printf("%s/n",p->next->data);

ListNode *temp=p->next;

p->next=p->next->next;

free(temp);

temp=NULL;

count=0;

}

else

{

p=p->next;

count++;

}

}

printf("%s",p->data);

return 0;

}

3.POJ 1012 Joseph

我感覺這個應該稱爲新約瑟夫序列問題吧。和以前的有些區別,我用了個笨笨的方法,窮舉,我用的是鏈表,約瑟夫序列暫時只會鏈表。但是結果超時了,呵呵,我會盡快想個更好的方法。

而且我寫的這個鏈表和其它的不太一樣,加了個對下一個節點的備份。。。我也不知道該怎麼表達,因爲窮舉的時候要對鏈表一些節點的next指針修改,而按值傳遞效率又太低,所以就加了個這個。

#include<iostream>

using namespace std;

struct List

{

int data;

List *next;

List *preNext;

};

List *Create(int k)

{

//k個好人,因此需建立k*2個節點 

List *head,*tail,*p;

head=tail=p=NULL;

for(int n=0;n<k*2;n++)

{

p=new List;

p->data=n+1;

p->next=NULL;

p->preNext=NULL;

if(head==NULL)

{

head=p;

}

else

{

tail->next=p;

tail->preNext=p;

}

tail=p;

tail->next=head;

tail->preNext=head;

}

return tail;

}

bool Joseph(List *list,int k,int m)

{

//k個好人,k個壞人

//m值是否符合題意 

//list:尾節點 

bool b=false;

int n;

List *p=list; 

int num=0;//被刪去的人的個數 

while(num<k)

{

for(n=0;n<m-1;n++)

{

p=p->next;

}

if(p->next->data<=k)//刪掉的是好人 

{

break;

}

else//刪掉的是壞人 

{

num++;

p->next=p->next->next;

}

}

if(num==k)

{

b=true;

}

for(n=0;n<k*2;n++)

{

list->next=list->preNext;

list=list->next;

}

return b;

}

int FindM(List *list,int k)

{

for(int m=k+1;1;m++)

{

if(Joseph(list,k,m))

{

return m;

}

}

}

int main()

{

int n;

List *list=NULL;

while(1)

{

cin>>n;

if(n<0||n>=14)

{

continue;

}

else if(n==0)

{

break;

}

else

{

list=Create(n);

cout<<FindM(list,n)<<endl;

}

}

return 0;

}

4.POJ 1664 放蘋果

遞歸,純遞歸,太純了!代把n個蘋果放到m個盤子裏邊,分幾種情況:

1.蘋果少於盤子,那麼多的盤子就沒用了

2.蘋果多於盤子,這時就可以遞歸了,我的想法是先在m個盤子裏邊每個都放上一個蘋果,然後再遞歸地放剩下的,再加上空一個盤子的(其實不只是空一個盤子,應該是至少空一個盤子)。

關鍵代碼:

int apples(int m,int n)

{

if(m==0||n==1)

{

return 1;

}

else if(m<n)

{

return apples(m,m);

}

else

{

return apples(m-n,n)+apples(m,n-1);

}

}

發佈了36 篇原創文章 · 獲贊 4 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章