資訊學奧賽一本通(C++版) 第三部分 資料結構 第三章 樹
阿新 • • 發佈:2018-12-30
//1336 【例3-1】找樹根和孩子
//提交,未通過,明白了,孩子必須按字典序輸出
//修改,提交,AC 2017-12-13 18:54
//該題思路可以預計,與書中提供的程式碼很不相同,書中猜測用的是左子右兄表示法,日後驗證
//該題,本人思路,鄰接表,有向圖.
//很明顯,水平上了一個臺階。
#include <stdio.h>
#include <string.h>
int parent[110],head[110],cnt=0,d[110];//parent[i]節點i的父親,d[i]儲存max的孩子
struct node{
int to,next;
}e[210];//有向圖
void add_edge(int u,int v){
cnt++,e[cnt].to=v,e[cnt].next=head[u],head[u]=cnt;
}
int main(){
int x,y,n,m,i,max=0,b,count,j,t;
memset(parent,0,sizeof(parent));
scanf("%d%d",&n,&m);
for(i=1;i<=m;i++){
scanf("%d%d",&x,&y);
parent[y]=x,add_edge(x,y);
}
for(i=1;i<=n;i++)//找root
if(parent[i]==0)printf("%d\n",i);
for(i=1;i<=n;i++){//找孩子最多的節點
count=0;
for(b=head[i];b;b=e[b].next)
count++;
if(count>max)max=count,j=i;
}
count=0;
for(b=head[j];b;b=e[b].next)d[count++]=e[b].to;//儲存孩子
printf("%d\n",j);
for(i=0;i<count;i++)//自小到大排序
for(j=i+1;j<count;j++)
if(d[i]>d[j])t=d[i],d[i]=d[j],d[j]=t;
for(i=0;i<count;i++)printf("%d ",d[i]);
return 0;
}
//1337 【例3-2】單詞查詢樹
//首先明確,是一棵樹,而不是二叉樹
//第一直覺是採用樹的處理方式,至少是遞迴
//無奈,眼高手低,
//搜尋網路,https://www.cnblogs.com/sssy/p/6640480.html此文程式碼寫得不錯,雖然沒有什麼說明,但還是看懂程式碼了
//經檢驗,上述程式碼AC,可以開始獨立編寫了
//樣例通過,提交 測試點4 答案錯誤
//靜態閱讀程式碼,發現 漏了 讀入的字串 排序
//新增,提交,AC 2017-12-19 18:40
#include <stdio.h>
#include <string.h>
char a[32000][70];
void quicksort(int left,int right){//字串處理的快排,自小到大排序
int i=left,j=right,mid=(left+right)/2;
char b[70];
while(i<=j){
while(strcmp(a[i],a[mid])<0)i++;
while(strcmp(a[mid],a[j])<0)j--;
if(i<=j){
strcpy(b,a[i]);
strcpy(a[i],a[j]);
strcpy(a[j],b);
i++,j--;
}
}
if(i<right)quicksort(i,right);
if(left<j)quicksort(left,j);
}
int main(){
int ans,i=0,j,len;
while(scanf("%s",a[i])!=EOF)i++;//字串序列讀取,序列從0開始
len=i;
quicksort(0,len-1);//遺漏此句 ,測試點4 答案錯誤
ans=strlen(a[0]);
for(i=1;i<len;i++){
j=0;
while(a[i-1][j]==a[i][j])j++;//查尋雷同部分
ans+=strlen(a[i])-j;//不同部分,就需開新節點來儲存
}
ans+=1;//加上root元素
printf("%d",ans);
return 0;
}
//1338 【例3-3】醫院設定
//https://www.cnblogs.com/harden/p/5596801.html看了文中才明白,要用Floyd演算法,想象與現實差距太大
//樣例通過,提交AC 2017-12-20
#include <stdio.h>
#include <string.h>
#define INF 999999999
int a[110][110],b[110],d[110];
int main(){
int i,j,n,k,left,right,min=INF;//此處寫成 min=0 昏招
memset(d,0,sizeof(d));
scanf("%d",&n);
for(i=1;i<=n;i++)//矩陣初始化
for(j=1;j<=n;j++)
if(i==j)a[i][j]=0;
else a[i][j]=INF;
for(i=1;i<=n;i++){
scanf("%d%d%d",&b[i],&left,&right);
if(left!=0)a[i][left]=a[left][i]=1;//無向圖
if(right!=0)a[i][right]=a[right][i]=1;
}
for(k=1;k<=n;k++)//Floyd演算法
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(a[i][j]>a[i][k]+a[k][j])
a[i][j]=a[i][k]+a[k][j];
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
d[i]+=a[i][j]*b[j];
for(i=1;i<=n;i++)
if(d[i]<min)
min=d[i];
printf("%d",min);
return 0;
}
//1339 【例3-4】求後序遍歷
//樣例通過,提交,測試點3-5 答案錯誤
//急尋測試資料
//提供一組測試資料
//輸入資料
//abdcef
//bdaecf
//輸出資料
//dbefca
//核心,先序字串對應先序字串,中序字串對應中序字串
//筆誤造成排查很久,for(i=len2+1;i<len1;i++)e[i-(len2+1)]=a[i];//此處寫成 e[i-(len2+1)]=b[i] 昏招,修改,提交AC 2017-12-14
#include <stdio.h>
#include <string.h>
char pre[100],in[100];
void PostOrder(char *a,char *b){//a先序 b中序
char c[100],d[100],e[100],f[100];//c先序 d中序 e先序 f中序
//提交,未通過,明白了,孩子必須按字典序輸出
//修改,提交,AC 2017-12-13 18:54
//該題思路可以預計,與書中提供的程式碼很不相同,書中猜測用的是左子右兄表示法,日後驗證
//該題,本人思路,鄰接表,有向圖.
//很明顯,水平上了一個臺階。
#include <stdio.h>
#include <string.h>
int parent[110],head[110],cnt=0,d[110];//parent[i]節點i的父親,d[i]儲存max的孩子
struct node{
int to,next;
}e[210];//有向圖
void add_edge(int u,int v){
cnt++,e[cnt].to=v,e[cnt].next=head[u],head[u]=cnt;
}
int main(){
int x,y,n,m,i,max=0,b,count,j,t;
memset(parent,0,sizeof(parent));
scanf("%d%d",&n,&m);
for(i=1;i<=m;i++){
scanf("%d%d",&x,&y);
parent[y]=x,add_edge(x,y);
}
for(i=1;i<=n;i++)//找root
if(parent[i]==0)printf("%d\n",i);
for(i=1;i<=n;i++){//找孩子最多的節點
count=0;
for(b=head[i];b;b=e[b].next)
count++;
if(count>max)max=count,j=i;
}
count=0;
for(b=head[j];b;b=e[b].next)d[count++]=e[b].to;//儲存孩子
printf("%d\n",j);
for(i=0;i<count;i++)//自小到大排序
for(j=i+1;j<count;j++)
if(d[i]>d[j])t=d[i],d[i]=d[j],d[j]=t;
for(i=0;i<count;i++)printf("%d ",d[i]);
return 0;
}
//1337 【例3-2】單詞查詢樹
//首先明確,是一棵樹,而不是二叉樹
//第一直覺是採用樹的處理方式,至少是遞迴
//無奈,眼高手低,
//搜尋網路,https://www.cnblogs.com/sssy/p/6640480.html此文程式碼寫得不錯,雖然沒有什麼說明,但還是看懂程式碼了
//經檢驗,上述程式碼AC,可以開始獨立編寫了
//樣例通過,提交 測試點4 答案錯誤
//靜態閱讀程式碼,發現 漏了 讀入的字串 排序
//新增,提交,AC 2017-12-19 18:40
#include <stdio.h>
#include <string.h>
char a[32000][70];
void quicksort(int left,int right){//字串處理的快排,自小到大排序
int i=left,j=right,mid=(left+right)/2;
char b[70];
while(i<=j){
while(strcmp(a[i],a[mid])<0)i++;
while(strcmp(a[mid],a[j])<0)j--;
if(i<=j){
strcpy(b,a[i]);
strcpy(a[i],a[j]);
strcpy(a[j],b);
i++,j--;
}
}
if(i<right)quicksort(i,right);
if(left<j)quicksort(left,j);
}
int main(){
int ans,i=0,j,len;
while(scanf("%s",a[i])!=EOF)i++;//字串序列讀取,序列從0開始
len=i;
quicksort(0,len-1);//遺漏此句 ,測試點4 答案錯誤
ans=strlen(a[0]);
for(i=1;i<len;i++){
j=0;
while(a[i-1][j]==a[i][j])j++;//查尋雷同部分
ans+=strlen(a[i])-j;//不同部分,就需開新節點來儲存
}
ans+=1;//加上root元素
printf("%d",ans);
return 0;
}
//1338 【例3-3】醫院設定
//https://www.cnblogs.com/harden/p/5596801.html看了文中才明白,要用Floyd演算法,想象與現實差距太大
//樣例通過,提交AC 2017-12-20
#include <stdio.h>
#include <string.h>
#define INF 999999999
int a[110][110],b[110],d[110];
int main(){
int i,j,n,k,left,right,min=INF;//此處寫成 min=0 昏招
memset(d,0,sizeof(d));
scanf("%d",&n);
for(i=1;i<=n;i++)//矩陣初始化
for(j=1;j<=n;j++)
if(i==j)a[i][j]=0;
else a[i][j]=INF;
for(i=1;i<=n;i++){
scanf("%d%d%d",&b[i],&left,&right);
if(left!=0)a[i][left]=a[left][i]=1;//無向圖
if(right!=0)a[i][right]=a[right][i]=1;
}
for(k=1;k<=n;k++)//Floyd演算法
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(a[i][j]>a[i][k]+a[k][j])
a[i][j]=a[i][k]+a[k][j];
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
d[i]+=a[i][j]*b[j];
for(i=1;i<=n;i++)
if(d[i]<min)
min=d[i];
printf("%d",min);
return 0;
}
//1339 【例3-4】求後序遍歷
//樣例通過,提交,測試點3-5 答案錯誤
//急尋測試資料
//提供一組測試資料
//輸入資料
//abdcef
//bdaecf
//輸出資料
//dbefca
//核心,先序字串對應先序字串,中序字串對應中序字串
//筆誤造成排查很久,for(i=len2+1;i<len1;i++)e[i-(len2+1)]=a[i];//此處寫成 e[i-(len2+1)]=b[i] 昏招,修改,提交AC 2017-12-14
#include <stdio.h>
#include <string.h>
char pre[100],in[100];
void PostOrder(char *a,char *b){//a先序 b中序
char c[100],d[100],e[100],f[100];//c先序 d中序 e先序 f中序