A1004
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 110;
int n, m;
int h[N], e[N], ne[N], idx;
int cnt[N], max_depth;
void add(int a, int b)
{
e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}
void dfs(int u, int depth)
{
if (h[u] == -1) // 说明u是叶子节点
{
cnt[depth] ++ ;
max_depth = max(max_depth, depth);
return;
}
for (int i = h[u]; ~i; i = ne[i])
dfs(e[i], depth + 1);
}
int main()
{
cin >> n >> m;
memset(h, -1, sizeof h);
for (int i = 0; i < m; i ++ )
{
int id, k;
cin >> id >> k;
while (k -- )
{
int son;
cin >> son;
add(id, son); //从id指向son 有一条 边
}
}
dfs(1, 0);
cout << cnt[0];
for (int i = 1; i <= max_depth; i ++ ) cout << ' ' << cnt[i];
cout << endl;
return 0;
}
A1020
#include<iostream>
#include<unordered_map>
using namespace std;
const int maxn=31;
int postorder[maxn],inorder[maxn];
int q[maxn];
unordered_map<int,int> l,r,pos;
int n;
int build(int il,int ir,int pl,int pr)
{
int root=postorder[pr];
int k=pos[root];
if(il<k)
l[root]=build(il,k-1,pl,pl+k-1-il);
if(k<ir)
r[root]=build(k+1,ir,pl+k-il,pr-1);
return root;
}
void bfs(int root)
{
int hh=0,ss=0;
q[0]=root;
while(hh<=ss)
{
int t=q[hh++];
if(l.count(t))
q[++ss]=l[t];
if(r.count(t))
q[++ss]=r[t];
}
cout << q[0];
for(int i=1; i<n; i++)
cout << " " << q[i];
}
int main()
{
cin >> n;
for(int i=0; i<n; i++)
{
cin >> postorder[i];
}
for(int i=0; i<n; i++)
{
cin >> inorder[i];
pos[inorder[i]]=i;
}
int root=build(0,n-1,0,n-1);
bfs(root);
}
A1043
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1010;
int n;
int preorder[N], inorder[N];
int postorder[N], cnt;
bool build(int il, int ir, int pl, int pr, int type)
{
if (il > ir) return true;
int root = preorder[pl]; //根节点
int k;
if (type == 0) //表示 普通的 二叉树 遍历
{
for (k = il; k <= ir; k ++ ) //左子树是严格小于根节点,所以在inorder中有两个个root相同,当然选择第1个
if (inorder[k] == root)
break;
if (k > ir) return false;
}
else //镜像 二叉树
{
for (k = ir; k >= il; k -- ) //我们已经 将中序 遍历的 结果,扭转过来了,但是如果遇到上面的情况,需要选择后面那个
if (inorder[k] == root)
break;
if (k < il) return false;
}
bool res = true;
if (!build(il, k - 1, pl + 1, pl + 1 + (k - 1 - il), type)) res = false;
if (!build(k + 1, ir, pl + 1 + (k - 1 - il) + 1, pr, type)) res = false;
postorder[cnt ++ ] = root; //后序遍历的方式 ,就是 先左子树再右子树,再根节点,前面两个if中,就已经遍历左子树和右子树了
return res;
}
int main()
{
cin >> n;
for (int i = 0; i < n; i ++ )
{
cin >> preorder[i];
inorder[i] = preorder[i];
}
sort(inorder, inorder + n); //inorder就是 二叉树 中序遍历
if (build(0, n - 1, 0, n - 1, 0)) //判断是否能够 重建 成功
{
puts("YES");
cout << postorder[0];
for (int i = 1; i < n; i ++ ) cout << ' ' << postorder[i];
cout << endl;
}
else
{
reverse(inorder, inorder + n);
cnt = 0;
if (build(0, n - 1, 0, n - 1, 1))
{
puts("YES");
cout << postorder[0];
for (int i = 1; i < n; i ++ ) cout << ' ' << postorder[i];
cout << endl;
}
else puts("NO");
}
return 0;
}
A1064
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1010;
int n;
int w[N], tr[N];
void dfs(int u, int& k) // 中序遍历
{
if (u * 2 <= n) dfs(u * 2, k);
tr[u] = w[k ++ ];
if (u * 2 + 1 <= n) dfs(u * 2 + 1, k);
}
int main()
{
cin >> n;
for (int i = 0; i < n; i ++ ) cin >> w[i]; //输入w数组
sort(w, w + n); //直接排序
int k = 0;
dfs(1, k); //k去遍历w数组
cout << tr[1];
for (int i = 2; i <= n; i ++ ) cout << ' ' << tr[i];
cout << endl;
return 0;
}
A1099
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 110;
/*
通过中序遍历的方式 将权值 放到 二叉树中
直接层序遍历 二叉树
*/
int n;
int l[N], r[N];
int a[N], w[N];
int q[N];
void dfs(int u, int& k) //对数组a 通过 中序遍历的 方式 建立二叉树
{
if (u == -1) return;
dfs(l[u], k);
w[u] = a[k ++ ]; //w的数组下标表示 节点,元素值表示权值
dfs(r[u], k);
}
void bfs() //层序遍历 没有参数
{
int hh = 0, tt = 0;
q[0] = 0; //q的元素值表示的是下标
while (hh <= tt)
{
int t = q[hh ++ ];
if (l[t] != -1) q[ ++ tt] = l[t];
if (r[t] != -1) q[ ++ tt] = r[t];
}
cout << w[q[0]];
for (int i = 1; i < n; i ++ ) cout << ' ' << w[q[i]];
}
int main()
{
cin >> n; //输入n
for (int i = 0; i < n; i ++ ) cin >> l[i] >> r[i]; //输入 左节点 和 右节点
for (int i = 0; i < n; i ++ ) cin >> a[i]; //输入权值
sort(a, a + n); //对权值 进行排序
int k = 0;
dfs(0, k); //用k去遍历a
bfs();
return 0;
}
A1102
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 15;
int n;
int l[N], r[N];
int q[N];
bool has_father[N];
void dfs_reverse(int u)
{
if (u == -1) return;
dfs_reverse(l[u]);
dfs_reverse(r[u]);
swap(l[u], r[u]);
}
void bfs(int root)
{
int hh = 0, tt = 0;
q[0] = root;
while (hh <= tt)
{
int t = q[hh ++ ];
if (l[t] != -1) q[ ++ tt] = l[t];
if (r[t] != -1) q[ ++ tt] = r[t];
}
cout << q[0];
for (int i = 1; i < n; i ++ ) cout << ' ' << q[i];
cout << endl;
}
int flag=1;
void dfs(int u, int& k)
{
if (u == -1) return;
dfs(l[u], k);
if(flag!=1) //行末不能有空格
cout << " ";
cout << u;
flag++;
dfs(r[u], k);
}
int main()
{
cin >> n;
memset(l, -1, sizeof l);
memset(r, -1, sizeof r);
for (int i = 0; i < n; i ++ )
{
char lc, rc;
cin >> lc >> rc;
if (lc != '-') l[i] = lc - '0', has_father[l[i]] = true; //标记lc有 父亲 节点
if (rc != '-') r[i] = rc - '0', has_father[r[i]] = true; //标记rc有父亲节点
}
int root = 0;
while (has_father[root]) root ++ ;
dfs_reverse(root); //将左右子树扭转
bfs(root); //层序遍历 输出
int k = 0;
dfs(root, k);
return 0;
}
A1110
#include<iostream>
#include<cstring>
using namespace std;
const int maxn=22;
int n;
int maxnn=0,maxid;
int l[maxn],r[maxn];
bool is_root[maxn];
void dfs(int u,int k)
{
if(u==-1)
return ;
if(k>maxnn)
{
maxnn=k;
maxid=u;
}
dfs(l[u],k*2);
dfs(r[u],k*2+1);
}
int main()
{
cin >> n;
memset(l,-1,sizeof l);
memset(r,-1,sizeof r);
for(int i=0; i<n; i++)
{
string a,b;
cin >> a >> b;
if(a!="-") //如果是 -33 -44 这些数字肯定可以 但是 你用a[0]=='-' b[0]=='-' 判断 肯定不行
{
l[i]=stoi(a);
is_root[l[i]]=true;
}
if(b!="-")
{
r[i]=stoi(b);
is_root[r[i]]=true;
}
}
int root=0;
while(is_root[root])
root++;
dfs(root,1);
if(maxnn==n)
cout << "YES " << maxid;
else
cout << "NO " << root;
return 0;
}
A1115
#include<iostream>
using namespace std;
const int maxn=1111;
int n,idx;
int l[maxn],r[maxn],v[maxn],max_depth=0,cnt[maxn];
void insert(int &u,int w) //插入函数的思路就是,如果当前的值小于等于根节点的,则插入到左子树中,如果当前的值大于右子树,插入到右子树中,所以用v存放各个节点值
{
if(!u)
{
u=++idx;
v[u]=w;
}
else if(w<=v[u])
insert(l[u],w); //其实这个 l,r分别存放的是,节点的左右下标,根节点从1开始
else
insert(r[u],w);
}
void dfs(int root,int depth)
{
if(!root)
return ;
cnt[depth]++; //记录每一层节点的个数
max_depth=max(depth,max_depth); //更新最大深度
dfs(l[root],depth+1); //进行左右子树递归
dfs(r[root],depth+1);
}
int main()
{
cin >> n;
int root=0; //设置root为0,表示没有意义的点
for(int i=0; i<n; i++) //边输入边插入
{
int w;
cin >> w;
insert(root,w);
}
dfs(root,1); //从根节点出发
printf("%d + %d = %d",cnt[max_depth],cnt[max_depth-1],cnt[max_depth]+cnt[max_depth-1]);
return 0;
}
A1123
#include<iostream>
using namespace std;
const int maxn=33;
int n;
int v[maxn],h[maxn],l[maxn],r[maxn],idx;
void update(int &u)
{
h[u]=max(h[l[u]],h[r[u]])+1;
}
void R(int &u)
{
int p=l[u];
l[u]=r[p];
r[p]=u;
update(p),update(u);
u=p;
}
void L(int &u)
{
int p=r[u];
r[u]=l[p];
l[p]=u;
update(p),update(u);
u=p;
}
int get_balance(int u)
{
return h[l[u]]-h[r[u]];
}
void insert(int &u,int w)
{
if(!u)
{
u=++idx;
v[u]=w;
}
else if(w<v[u])
{
insert(l[u],w);
if(get_balance(u)==2)
{
if(get_balance(l[u])==1)
R(u);
else
{
L(l[u]);
R(u);
}
}
}
else
{
insert(r[u],w);
if(get_balance(u)==-2)
{
if(get_balance(r[u])==-1)
L(u);
else
{
R(r[u]);
L(u);
}
}
}
update(u);
}
int q[maxn],pos[maxn];
bool bfs(int root)
{
int hh = 0, tt = 0;
q[0] = root;
pos[root] = 1;
bool res = true;
while (hh <= tt)
{
int t = q[hh ++ ];
if (pos[t] > n) res = false; //这个不像build那个建树,这个是用l[t]判断左子树是否 存在,同时用r[t]判断右子树 是否 存在
if (l[t]) q[ ++ tt] = l[t], pos[l[t]] = pos[t] * 2; // 按照根节点为x,左子树为2*x,右子树为2*x+1的 方式 放入数字,最后判断其值是否 大于n
if (r[t]) q[ ++ tt] = r[t], pos[r[t]] = pos[t] * 2 + 1;
}
return res;
}
int main()
{
int root = 0;
cin >> n; //输入n
for (int i = 0; i < n; i ++ )
{
int w;
cin >> w;
insert(root, w); //通过 AVL进行 建树
}
bool res=bfs(root); //也是 宽搜
cout << v[q[0]];
for(int i=1; i<n; i++)
cout << " " << v[q[i]];
cout << endl;
if (res) puts("YES");
else puts("NO");
return 0;
}
A1135
#include <iostream>
#include <algorithm>
#include <unordered_map>
using namespace std;
const int N = 40;
int pre[N], in[N];
unordered_map<int, int> pos;
bool ans;
/*
判断 红黑树 的 4个 方法
1.根节点是 黑色
2.每个叶子结点 是黑色
3.如果 一个 节点是 红色,则 他的 两个 孩子都是 黑色
4.从根节点到叶子结点,其中 黑色节点的个数 相同
*/
int build(int il, int ir, int pl, int pr, int& sum)
{
int root = pre[pl];
int k = pos[abs(root)];
if (k < il || k > ir) //有可能 给出的 前序 遍历的值 是 不合法的,所以 遍历 下
{
ans = false;
return 0;
}
int left = 0, right = 0, ls = 0, rs = 0;
if (il < k) left = build(il, k - 1, pl + 1, pl + 1 + k - 1 - il, ls);
if (k < ir) right = build(k + 1, ir, pl + 1 + k - 1 - il + 1, pr, rs);
if (ls != rs) ans = false; //ls表示 左 子树中 黑色 节点的 个数,rs表示 右子树 中 黑色 节点的个数
sum = rs; //这个sum为ls或者rs均可
if (root < 0) //根节点为红色时,如果任何一个孩子为黑色 直接ans为false
{
if (left < 0 || right < 0) ans = false;
}
else sum ++ ; //否则就表示 root为黑色,sum++
return root;
}
int main()
{
int T;
cin >> T;
while (T -- )
{
int n;
cin >> n;
pos.clear();
for (int i = 0; i < n; i ++ )
{
cin >> pre[i];
in[i] = abs(pre[i]);
}
sort(in, in + n);
for (int i = 0; i < n; i ++ ) pos[in[i]] = i;
ans = true;
int sum;
int root = build(0, n - 1, 0, n - 1, sum); //sum其实统计的是黑色节点的个数
if (root < 0) ans = false;
if (ans) puts("Yes");
else puts("No");
}
return 0;
}
A1053
#include <iostream>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 110;
int n, m, S;
int w[N];
bool g[N][N];
vector<vector<int>> ans;
void dfs(int u, int s, vector<int> &path)
{
bool is_leaf = true;
for (int i = 0; i < n; i ++ )
if (g[u][i])
{
is_leaf = false;
break;
}
if (is_leaf) //到了 根节点时,将 整个 路径 放到 ans中
{
if (s == S) ans.push_back(path);
}
else //否则,表示 没有 到达 根节点
{
for (int i = 0; i < n; i ++ )
if (g[u][i])
{
path.push_back(w[i]); //这个 相当于 从 i出发
dfs(i, s + w[i], path);
path.pop_back(); //首先这个 popback是pop掉 最后一个值,而其中 从 i出发可以走,从跟i同一层的点 出发 也可以走,所以需要将 之前走i 那个点 给他pop 掉
}
}
}
int main()
{
cin >> n >> m >> S;
for (int i = 0; i < n; i ++ ) cin >> w[i];
while (m -- )
{
int id, k;
cin >> id >> k; //id表示 父亲节点 k表示 孩子的 个数
while (k -- )
{
int son;
cin >> son;
g[id][son] = true; //从id到son进行 标记
}
}
vector<int> path({w[0]}); //这是 对path 进行 赋初始值
dfs(0, w[0], path);
sort(ans.begin(), ans.end(), greater<vector<int>>());
for (auto p : ans)
{
cout << p[0];
for (int i = 1; i < p.size(); i ++ ) cout << ' ' << p[i];
cout << endl;
}
return 0;
}
A1079
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int N = 100010;
int n;
double P, R;
int p[N], f[N], c[N]; //数组p是 存储每个节点的 父亲节点,f表示 从当前节点
int dfs(int u) //dfs 返回的是 到达 根节点的 层数
{
if (f[u] != -1) return f[u]; //如果 这个点 是 存在的 直接 返回f[u]
if (p[u] == -1) return f[u] = 0; //表示是 根节点 返回 0
return f[u] = dfs(p[u]) + 1; //这个 表示 从 u节点出发到根节点的距离 为 从他的父亲节点p[u]出发到根节点的距离+1
}
int main()
{
cin >> n >> P >> R; //输入 n个节点,P表示 单价,R表示概率
memset(p, -1, sizeof p); //对p进行 初始化
for (int i = 0; i < n; i ++ )
{
int k;
cin >> k;
for (int j = 0; j < k; j ++ )
{
int son;
cin >> son;
p[son] = i;
}
if (!k) cin >> c[i]; //输入 节点的 权值
}
memset(f, -1, sizeof f); //对f初始化为 -1
double res = 0;
for (int i = 0; i < n; i ++ )
if (c[i])
res += c[i] * P * pow(1 + R / 100, dfs(i)); //dfs应该是 返回 当前的 深度
printf("%.1lf\n", res);
return 0;
}
A1090
#include <iostream>
#include <cstring>
#include <cmath>
using namespace std;
const int N = 100010;
int n;
double P, R;
int p[N], f[N];
int dfs(int u)
{
if (f[u] != -1) return f[u];
if (p[u] == -1) return f[u] = 0;
return f[u] = dfs(p[u]) + 1;
}
int main()
{
cin >> n >> P >> R;
for (int i = 0; i < n; i ++ ) cin >> p[i];
memset(f, -1, sizeof f);
int res = 0, cnt = 0;
for (int i = 0; i < n; i ++ )
if (dfs(i) > res)
{
res = dfs(i);
cnt = 1;
}
else if (dfs(i) == res) cnt ++ ;
printf("%.2lf %d\n", P * pow(1 + R / 100, res), cnt);
return 0;
}
A1155
/*
1.根据完全二叉的层序数组,来判断是大顶堆,小顶堆还是不是堆
2.下标从1,开始,左孩子是2*x 右孩子是2*x+1
这道题的核心 思路 是,
*/
#include<iostream>
#include<vector>
using namespace std;
const int maxn=1111;
int cengxu[maxn];
int n;
vector<int> path;
bool lt,gt;
/*
现在 想像 成 只有 3个点,根节点,左孩子,右孩子,首先 将 根节点 放到path中,然后 遍历左孩子然后 在 右孩子,但是
在函数 返回中 先 访问的 是 右边的值
*/
void dfs(int root) //从根节点 出发
{
path.push_back(cengxu[root]);
if(root*2>n) //表示 已经到了 叶子节点
{
cout << path[0];
for(int i=1; i<path.size(); i++)
{
cout << " " << path[i];
if(path[i]>path[i-1])
gt=true;
if(path[i]<path[i-1])
lt=true;
}
cout << endl;
}
if(root*2+1<=n) //先 遍历 左边的 值,然后 再 遍历 右边的值,
dfs(root*2+1);
if(root*2<=n)
dfs(root*2);
path.pop_back();
}
int main()
{
cin >> n;
for(int i=1; i<=n; i++)
{
cin >> cengxu[i]; //输入 层序的 数组
}
dfs(1);
if(gt && lt)
cout << "Not Heap" << endl;
else if(gt)
cout << "Min Heap" << endl;
else
cout << "Max Heap" << endl;
return 0;
}
A1130
#include <iostream>
using namespace std;
const int N = 25;
int n;
int l[N], r[N];
string w[N];
bool st[N], is_leaf[N];
string dfs(int u)
{
string left, right;
if (l[u] != -1) //如果 左节点 存在
{
left = dfs(l[u]); //递归 深搜 左节点
if (!is_leaf[l[u]]) left = "(" + left + ")"; //不是 叶子结点 就 左右 加 括号
}
if (r[u] != -1)
{
right = dfs(r[u]);
if (!is_leaf[r[u]]) right = "(" + right + ")";
}
return left + w[u] + right;
}
int main()
{
cin >> n; // 输入 n个节点
for (int i = 1; i <= n; i ++ )
{
cin >> w[i] >> l[i] >> r[i];
if (l[i]) st[l[i]] = true; //这是 为了 后面 去 寻找 根节点
if (r[i]) st[r[i]] = true;
if (l[i] == -1 && r[i] == -1) is_leaf[i] = true; //这是 为了 去 寻找 叶子结点,其中 题目的 意思 是 通过 中序 遍历的 方式,给 左子树加括号,或者 右子树 加括号
}
int root = 1;
while (st[root]) root ++ ; //这是 为了 找到 根节点
cout << dfs(root) << endl; //直接 深搜
return 0;
}
A1143
#include<iostream>
#include<map>
#include<algorithm>
using namespace std;
const int maxn=101000;
int n,m;
map<int,int> mp;
int seq[maxn],in[maxn],fuck[maxn],fuck1[maxn],pre[maxn],p[maxn],depth[maxn];
int build(int preL,int preR,int inL,int inR,int d) //这个 还是 按照 根据 前序 遍历 数组和 中序 遍历 数组 找到 对应的 树
{
int root=pre[preL];
int k=root;
depth[root]=d;
if(inL<k)
{
p[build(preL+1,preL+(k-inL),inL,k-1,d+1)]=root; //build此时 返回的是 左孩子
}
if(k<inR)
{
p[build(preL+(k-inL)+1,preR,k+1,inR,d+1)]=root; //build此时 返回的 是 右孩子
}
return root;
}
int main()
{
cin >> m >> n;
for(int i=0; i<n; i++)
{
cin >> seq[i]; //seq表示 前序 遍历的 结果
fuck[i]=seq[i]; //fuck相当于 preorder的结果
}
sort(seq,seq+n); //seq相当于 inorder的结果
for(int i=0; i<n; i++)
{
mp[seq[i]]=i;
in[i]=i; //in相当于 inorder的映射
}
for(int i=0; i<n; i++)
{
pre[i]=mp[fuck[i]]; //pre相当于fuck的映射,通过 映射 只是降低 时间 复杂度
}
build(0,n-1,0,n-1,0);
int a,b;
while(m--)
{
cin >> a >> b;
if(mp.count(a) && mp.count(b)) //如果 在 映射 中找得到 a,b
{
a=mp[a],b=mp[b]; //得到 其 映射的值
int x=a,y=b;
while(a!=b) //这个 就是 求 最低 公共 子节点
{
if(depth[a]>depth[b]) //将深度 更大的 每个 节点 向上走
a=p[a]; //p数组 存放的 就是 映射的值
else
b=p[b];
}
if(a!=x && a!=y)
{
printf("LCA of %d and %d is %d.\n",seq[x],seq[y],seq[a]);
}
else if(a==x) //如果a==x,说明x是y的父亲节点
{
printf("%d is an ancestor of %d.\n",seq[x],seq[y]);
}
else //否则,说明 y是x的 父亲
{
printf("%d is an ancestor of %d.\n",seq[y],seq[x]);
}
}
else if(mp.count(a)==0 && mp.count(b)==0)
printf("ERROR: %d and %d are not found.\n",a,b);
else if(mp.count(a)==0)
printf("ERROR: %d is not found.\n",a);
else
printf("ERROR: %d is not found.\n",b);
}
return 0;
}