周學習總結
目錄:
第一個ACMer周,第一次沒日沒夜地刷水題,不知道爲什麼,睡眠明顯減少了,倒不是晚上睡不着,而是早晨很早就起牀,說白了,好像是沒有安全感,不謙虛地說:稍微有一點危機感。
學校的網絡中心招聘,我報了名,倒不是想搞網絡,主要是想讓他們給我提供一個方便的學習環境,但是根據朋友說的我發現我的想法好幼稚,呵呵。
這周大多數做的是水題,第一週嘛,但是也稍微做了幾個有技術含量的,多虧了強哥的指點,在這裏謝謝強哥了!但是強哥說的一點我沒有做到,不搜解題報告。有幾個題我實在沒有想法,所以就Google了一下,但是後來我自己寫了這些題目的變形題,保證不是特殊情況一定不搜!
這周把二叉樹的幾種遍歷寫了20遍,但是還不能做到關顯示器就敲出來,繼續努力吧。
令我欣慰的是,自從我統計以來代碼超過了1W,像這個速度,用不了一年就突破10W了。。。。。。
最近做題喜歡用C++,不知道C++裏可不可以用scanf和printf,反正好的編程習慣是肯定不允許這樣做的,但是scanf和printf確實可以讓程序效率變得高的多。這個問題我再考慮考慮吧。
下邊是我這周做的一部分題,附帶很詳細的分析過程。
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);
}
}