資料結構實驗三 2024_樹與圖實驗
7-1 根據後序和中序遍歷輸出前序遍歷
本題要求根據給定的一棵二叉樹的後序遍歷和中序遍歷結果,輸出該樹的前序遍歷結果。
輸入格式:
第一行給出正整數 n (≤30),是樹中結點的個數。隨後兩行,每行給出 n 個整數,分別對應後序遍歷和中序遍歷結果,數字間以空格分隔。題目保證輸入正確對應一棵二叉樹。
輸出格式:
在一行中輸出Preorder:
以及該樹的前序遍歷結果。數字間有1個空格,行末不得有多餘空格。
輸入樣例:
7
2 3 1 5 7 6 4
1 2 3 4 5 6 7
輸出樣例:
Preorder: 4 1 3 2 6 5 7
題目分析
- 根據中序遍歷和後序遍歷的得到前序遍歷的方法為,每次透過後序遍歷找到根節點,然後遞迴左右子樹,遞迴的方法為,在中序遍歷中計算出左子樹和右子樹的大小,然後在後序遍歷中確定左右子樹序列範圍
#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
int n,tot=0;
int a[50],b[50],ans[50];
int find(int l,int r,int x){
for(int i=l;i<=r;i++){
if(a[i]==x) return i;
}
return 0;
}
void dfs(int l1,int r1,int l2,int r2){
int rt=b[r2];//b[r2]為根節點
int id=find(l1,r1,rt);
ans[++tot]=rt;
if(id==0) return;
if(id>l1) dfs(l1,id-1,l2,r2-r1+id-1);
if(id<r1) dfs(id+1,r1,l2+id-l1,r2-1);
}
void solve(){
cin>>n;
for(int i=1;i<=n;i++) cin>>b[i];
for(int i=1;i<=n;i++) cin>>a[i];
dfs(1,n,1,n);
cout<<"Preorder: ";
for(int i=1;i<=n;i++) cout<<ans[i]<<" "[i==n];
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int T=1;
while(T--) solve();
return 0;
}
7-2 完全二叉樹的層序遍歷
一個二叉樹,如果每一個層的結點數都達到最大值,則這個二叉樹就是完美二叉樹。對於深度為 D 的,有 N 個結點的二叉樹,若其結點對應於相同深度完美二叉樹的層序遍歷的前 N 個結點,這樣的樹就是完全二叉樹。
給定一棵完全二叉樹的後序遍歷,請你給出這棵樹的層序遍歷結果。
輸入格式:
輸入在第一行中給出正整數 N(≤30),即樹中結點個數。第二行給出後序遍歷序列,為 N 個不超過 100 的正整數。同一行中所有數字都以空格分隔。
輸出格式:
在一行中輸出該樹的層序遍歷序列。所有數字都以 1 個空格分隔,行首尾不得有多餘空格。
輸入樣例:
8
91 71 2 34 10 15 55 18
輸出樣例:
18 34 55 71 2 10 15 91
題目分析
- 由於是完全二叉樹,根據完全二叉樹的性質可以知道,在層序遍歷中,若i為當前子樹根節點,則2i為左孩子節點,2i+1為右孩子節點,程式碼中用u<<1 與 u<<1|1表示左右孩子
- 那麼可以模擬後序遍歷的順序,計算出層序遍歷的答案
#include<bits/stdc++.h>
#define endl '\n'
#define lc u<<1
#define rc u<<1|1
using namespace std;
int n,tot=1;
int a[50],ans[50];
void dfs(int u){
if(u>n) return;
dfs(lc);
dfs(rc);
ans[u]=a[tot];
tot++;
}
void solve(){
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
dfs(1);
for(int i=1;i<=n;i++) cout<<ans[i]<<" "[i==n];
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int T=1;
while(T--) solve();
return 0;
}
7-3 最短工期
一個專案由若干個任務組成,任務之間有先後依賴順序。專案經理需要設定一系列里程碑,在每個里程碑節點處檢查任務的完成情況,並啟動後續的任務。現給定一個專案中各個任務之間的關係,請你計算出這個專案的最早完工時間。
輸入格式:
首先第一行給出兩個正整數:專案里程碑的數量 N(≤100)和任務總數 M。這裡的里程碑從 0 到 N−1 編號。隨後 M 行,每行給出一項任務的描述,格式為“任務起始里程碑 任務結束里程碑 工作時長”,三個數字均為非負整數,以空格分隔。
輸出格式:
如果整個專案的安排是合理可行的,在一行中輸出最早完工時間;否則輸出"Impossible"。
輸入樣例 1:
9 12
0 1 6
0 2 4
0 3 5
1 4 1
2 4 1
3 5 2
5 4 0
4 6 9
4 7 7
5 7 4
6 8 2
7 8 4
輸出樣例 1:
18
輸入樣例 2:
4 5
0 1 1
0 2 2
2 1 3
1 3 4
3 2 5
輸出樣例 2:
Impossible
題目分析
- 拓撲排序,每次取出入度為0的點,刪除該點與所有與該點相連的邊,(即所有與其相連的點入度-1),然後其相連點的答案,這裡用f[i]表示到達i點,滿足所有前驅已完成時至少需要花費的時間
- 注意判斷無解情況,即判斷該有向圖是否有環(拓撲拆圖之後若還有剩餘點則存在環)
#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
const int N=110;
struct node{
int to,w;
};
vector<node> g[N];
int n,m,tot=0;
int ind[N],f[N];
void topo(){
queue<int> q;
for(int i=0;i<n;i++){
if(ind[i]==0){
tot++;
q.push(i);
}
}
while(q.size()){
int u=q.front();
q.pop();
for(auto [v,w]:g[u]){
ind[v]--;
f[v]=max(f[v],f[u]+w);
if(ind[v]==0){
tot++;
q.push(v);
}
}
}
}
void solve(){
cin>>n>>m;
for(int i=1;i<=m;i++){
int u,v,w;cin>>u>>v>>w;
g[u].push_back({v,w});
ind[v]++;
}
topo();
int ans=0;
if(tot!=n){
cout<<"Impossible"<<endl;
return;
}
for(int i=0;i<n;i++) ans=max(ans,f[i]);
cout<<ans<<endl;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int T=1;
while(T--) solve();
return 0;
}
7-4 旅遊規劃
有了一張自駕旅遊路線圖,你會知道城市間的高速公路長度、以及該公路要收取的過路費。現在需要你寫一個程式,幫助前來諮詢的遊客找一條出發地和目的地之間的最短路徑。如果有若干條路徑都是最短的,那麼需要輸出最便宜的一條路徑。
輸入格式:
輸入說明:輸入資料的第 1 行給出 4 個正整數 n、m、s、d,其中 n(2≤n≤500)是城市的個數,順便假設城市的編號為 0~(n−1);m 是高速公路的條數;s 是出發地的城市編號;d 是目的地的城市編號。隨後的 m 行中,每行給出一條高速公路的資訊,分別是:城市 1、城市 2、高速公路長度、收費額,中間用空格分開,數字均為整數且不超過 500。輸入保證解的存在。
輸出格式:
在一行裡輸出路徑的長度和收費總額,數字間以空格分隔,輸出結尾不能有多餘空格。
輸入樣例:
4 5 0 3
0 1 1 20
1 3 2 30
0 3 4 10
0 2 2 20
2 3 1 20
輸出樣例:
3 40
題目分析
- 多權最短路模板,和dij寫法基本相同,只需要在運算子過載時判斷一下條件優先順序即可
#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
const int N=510;
int n,m,st,ed;
struct node{
int to,w,c;
bool operator< (const node rhs)const{
if(w!=rhs.w) return w>rhs.w; //大的優先順序小
else return c>rhs.c;
}
};
vector<node> g[N];
bool vis[N];
int dis[N],cost[N];
void dij(int x){
priority_queue<node> q;
dis[x]=0,cost[x]=0;
q.push({x,0,0});
while(!q.empty()){
auto t=q.top();
q.pop();
int u=t.to;
if(vis[u]) continue;
for(auto tmp:g[u]){
auto [v,w,c]=tmp;
if(dis[v]>dis[u]+w){
dis[v]=dis[u]+w;
cost[v]=cost[u]+c;
q.push({v,dis[v],cost[v]});
continue;
}
if(dis[v]==dis[u]+w && cost[v]>cost[u]+c){
dis[v]=dis[u]+w;
cost[v]=cost[u]+c;
q.push({v,dis[v],cost[v]});
}
}
}
}
void init(){
for(int i=0;i<=n+5;i++){
dis[i]=cost[i]=1e9;
vis[i]=0;
}
}
void solve(){
cin>>n>>m>>st>>ed;
init();
for(int i=1;i<=m;i++){
int u,v,w,c;cin>>u>>v>>w>>c;
g[u].push_back({v,w,c});
g[v].push_back({u,w,c});
}
dij(st);
cout<<dis[ed]<<" "<<cost[ed]<<endl;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int T=1;
while(T--) solve();
return 0;
}