数据结构实验三 2024_树与图实验
数据结构实验三 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;
}