树
列表
A1147 堆 比1155简单
//简单
#include<stdio.h>
#include<vector>
#include<stdlib.h>
#include<algorithm>
using namespace std;
vector<int>v1,v2,v3;
int n,m,temp,flag;
void downmaxAdjust(int low,int high){
int i=low,j=i*2;
while(j<=high){
if(j+1<=high&&v2[j+1]>v2[j]){
j=j+1;
}
if(v2[j]>v2[i]){
swap(v2[i],v2[j]);
i=j;
j=i*2;
}else break;
}
}
void downminAdjust(int low,int high){
int i=low,j=i*2;
while(j<=high){
if(j+1<=high&&v3[j+1]<v3[j]){
j=j+1;
}
if(v3[j]<v3[i]){
swap(v3[i],v3[j]);
i=j;
j=i*2;
}else break;
}
}
void Createmaxheap(){
for(int i=m/2;i>=1;i--){
downmaxAdjust(i,m);
}
}
void Createminheap(){
for(int i=m/2;i>=1;i--){
downminAdjust(i,m);
}
}
void postorder(int root){
if(root*2<=m)postorder(root*2);
if(root*2+1<=m)postorder(root*2+1);
printf("%d",v1[root]);
flag++;
if(flag!=m)printf(" ");
else printf("\n");
}
int main()
{
// freopen("input.txt","r",stdin);
scanf("%d %d",&n,&m);
for(int i=0;i<n;i++){ //调试的时候把n写成3了后来忘了改
v1.clear();
flag=0;
v1.push_back(-1);
for(int j=0;j<m;j++){
scanf("%d",&temp);
v1.push_back(temp);
}
v2=v3=v1;
Createmaxheap();
Createminheap();
if(v1==v2)printf("Max Heap\n");
else if(v1==v3)printf("Min Heap\n");
else printf("Not Heap\n");
postorder(1);
// printf("\n");
}
return 0;
}//函数 循环体意外进不去情况 原来是输入文件名写错了
// 什么鬼 测试样例过了 测试点一个也不对。。。
A1155 堆 输出路径题
#include<stdio.h>
#include<vector>
#include<stdlib.h>
#include<algorithm>
using namespace std;
vector<int>v1,v2,v3;
int n,temp;
vector<int>path;
void maxdownAdjust(int low,int high){
int i=low,j=i*2;
while(j<=high){
if(j+1<=high&&v2[j+1]>v2[j]){
j=j+1;
}
if(v2[j]>v2[i]){
swap(v2[j],v2[i]);
i=j;
j=i*2;
}else break;
}
}
void mindownAdjust(int low,int high){
int i=low,j=i*2;
while(j<=high){
if(j+1<=high&&v3[j+1]<v3[j]){
j=j+1;
}
if(v3[j]<v3[i]){
swap(v3[j],v3[i]);
i=j;
j=i*2;
}else break;
}
}
void createmaxheap(){
for(int i=n/2;i>=1;i--){
maxdownAdjust(i,n);
}
}
void createminheap(){
for(int i=n/2;i>=1;i--){
mindownAdjust(i,n);
}
}
int flag=0;
void DFS(int root){
if(root*2>n){
path.push_back(v1[root]);
for(int i=0;i<path.size();i++){
printf("%d",path[i]);
if(i!=path.size()-1)printf(" ");
}
printf("\n");
path.pop_back();
return;
}
path.push_back(v1[root]);
if(root*2+1<=n)DFS(root*2+1);
DFS(root*2);
path.pop_back();
}
int main()
{
// freopen("input.txt","r",stdin);
scanf("%d",&n);
v1.push_back(-1);
for(int i=0;i<n;i++){
scanf("%d",&temp);
v1.push_back(temp);
}
v2=v3=v1;
createmaxheap();
createminheap();
DFS(1);
if(v1==v2)printf("Max Heap\n");
else if(v1==v3)printf("Min Heap\n");
else printf("Not Heap\n");
return 0;
}
路径输出题 两个向下调整 两个建堆 判断是最大堆或是最小堆在DFS输出路径
A1098 堆排序
#include<stdio.h>
#include<algorithm>
#include<vector>
using namespace std;
int n;
void downAdjust(vector<int> &b,int low,int high){
int i=low,j=1*2;
while(j<=high){
if(j+1<=high&&b[j+1]>b[j]){
j=j+1;
}
if(b[j]>b[i]){
swap(b[j],b[i]);
i=j;
j=i*2;
}
}
}
int main()
{
scanf("%d",&n);
vector<int>a(n+1),b(n+1),c(n+1);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=n;i++)scanf("%d",&b[i]);
c=a;
int flag=0;
for(int i=2;i<=n;i++){
sort(c.begin()+1,c.begin()+1+i);
if(c==b){
flag=1;
printf("Insertion Sort\n");
sort(c.begin(),c.begin()+2+i);
for(int j=1;j<=n;j++){
printf("%d",c[j]);
if(j!=n)printf(" ");
}
break;
}
}
if(flag==0){
printf("Heap Sort\n");
sort(c.begin(),c.end());
int i;
for(i=n;i>=1;i--){
if(c[i]!=b[i])break;
}
swap(b[1],b[i]);
downAdjust(b,1,i-1);
for(i=1;i<=n;i++){
printf("%d",b[i]);
if(i!=n)printf(" ");
}
}
}
如果不是插入排序就是堆排序,判断堆排序排序点的位置从后往前判断
A1020 前中序构建二叉树 简单
#include<stdio.h>
#include<queue>
using namespace std;
struct node{
int data;
node* lchild;
node* rchild;
};
const int maxn=50;
int n;
int post[maxn],in[maxn];
int num=0;
node* create(int postl,int postr,int inl,int inr){
if(postl>postr){
return NULL;
}
node* root=new node;
root->data=post[postr];
int k;
for(k=inl;k<=inr;k++){
if(in[k]==post[postr])break;
}
int numleft=k-inl;
root->lchild=create(postl,postl+numleft-1,inl,k-1);
root->rchild=create(postl+numleft,postr-1,k+1,inr);
return root;
}
void Layerorder(node* root){
queue<node*>q;
q.push(root);
while(!q.empty()){
node* front=q.front();
q.pop();
printf("%d",front->data);
num++;
if(num!=n)printf(" ");
if(front->lchild!=NULL)q.push(front->lchild);
if(front->rchild!=NULL)q.push(front->rchild);
}
}
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d",&post[i]);
}
for(int i=0;i<n;i++){
scanf("%d",&in[i]);
}
node* root=create(0,n-1,0,n-1);
Layerorder(root);
return 0;
}
A1021 最深节点 图题 难
A1079 零售商 算总价
#include<stdio.h>
#include<vector>
#include<math.h>
using namespace std;
const int maxn=100010;
struct node{
int data;
vector<int>child;
}Node[maxn];
int n;
double p,r,num=0.0;
int m,temp1;
void DFS(int root,int index){
if(Node[root].child.size()==0){
num+=Node[root].data*pow(1+r,index)*p;
return;
}
for(int i=0;i<Node[root].child.size();i++){
DFS(Node[root].child[i],index+1);
}
}
int main()
{
scanf("%d %lf %lf",&n,&p,&r);
r/=100.0;
for(int i=0;i<n;i++){
scanf("%d",&m);
if(m!=0){
for(int j=0;j<m;j++){
scanf("%d",&temp1);
Node[i].child.push_back(temp1);
}
}else {
scanf("%d",&Node[i].data);
}
}
DFS(0,0);
printf("%.1lf\n",num);
return 0;
}
简单题,r记得除100
A1090 经销商问题 求最深节点深度、个数
Sroot for the root supplier is defined to be −1. 读题
注意一下输入找根节点。
#include<stdio.h>
#include<math.h>
#include<vector>
using namespace std;
const int maxn=100010;
vector<int>child[maxn];
double p,r;
int n,maxdepth=0,num=0;
void dfs(int index,int depth){
if(child[index].size()==0){
if(depth>maxdepth){
maxdepth=depth;
num=1;
}
else if(depth==maxdepth){
num++;
}
return;
}
for(int i=0;i<child[index].size();i++){
dfs(child[index][i],depth+1);
}
}
int main()
{
scanf("%d %lf %lf",&n,&p,&r);
r/=100;
int father,root;
for(int i=0;i<n;i++){
scanf("%d",&father);
if(father!=-1){
child[father].push_back(i);
}
else{
root=i;
}
}
dfs(root,0);
printf("%.2lf %d\n",p*pow(r+1,maxdepth),num);
return 0;
}
A1106 经销商 求最浅节点层次及个数 简单
#include<stdio.h>
#include<vector>
#include<math.h>
using namespace std;
const int maxn=100010;
vector<int>child[maxn];
int n,mindepth=maxn,sum=0;
double p,r;
void dfs(int index,int depth){
if(child[index].size()==0){
if(depth<mindepth){
mindepth=depth;
sum=1;
}
else if(depth==mindepth){
sum++;
}
return;
}
for(int i=0;i<child[index].size();i++){
dfs(child[index][i],depth+1);
}
}
int main()
{
scanf("%d %lf %lf",&n,&p,&r);
r/=100;
int n2,child2;
for(int i=0;i<n;i++){
scanf("%d",&n2);
for(int j=0;j<n2;j++){
scanf("%d",&child2);
child[i].push_back(child2);
}
}
dfs(0,0);
printf("%.4lf %d",p*pow(r+1,mindepth),sum);
return 0;
}
A1094 家族谱 求节点最多的层 及个数 简单
#include<stdio.h>
#include<vector>
using namespace std;
const int maxn=100010;
vector<int>child[maxn];
int layer[maxn]={0};
void dfs(int index,int depth){
layer[depth]++;
for(int i=0;i<child[index].size();i++){
dfs(child[index][i],depth+1);
}
}
int main()
{
int n,m,child1,n2,child2;
scanf("%d %d",&n,&m);
for(int i=0;i<m;i++){
scanf("%d %d",&child1,&n2);
for(int j=0;j<n2;j++){
scanf("%d",&child2);
child[child1].push_back(child2);
}
}
dfs(1,1);
int max=0,maxq=0;
for(int i=0;i<maxn;i++){
if(layer[i]>max){
max=layer[i];
maxq=i;
}
}
printf("%d %d\n",max,maxq);
return 0;
}
1004 家族谱 求每层叶子节点个数 简单
#include<stdio.h>
#include<vector>
using namespace std;
const int maxn=100010;
vector<int>child[maxn];
int layer[maxn]={0};
int maxdepth=0;
void dfs(int index,int depth){
if(child[index].size()==0){
layer[depth]++;
if(depth>maxdepth){
maxdepth=depth;
}
}
for(int i=0;i<child[index].size();i++){
dfs(child[index][i],depth+1);
}
}
int main()
{
int n1,m,father,n2,child2;
scanf("%d %d",&n1,&m);
for(int i=0;i<m;i++){
scanf("%d %d",&father,&n2);
for(int j=0;j<n2;j++){
scanf("%d",&child2);
child[father].push_back(child2);
}
}
dfs(1,1);
printf("%d",layer[1]);
for(int i=2;i<=maxdepth;i++){
printf(" %d",layer[i]);
}
return 0;
}
注意在DFS的时候就把最深层层数求出来
A1130 二叉树输出中缀表达式
#include<stdio.h>
#include<string>
#include<stdlib.h>
#include<iostream>
using namespace std;
const int maxn=25;
struct node{
string str;
int lchild,rchild;
}Node[maxn];
int isroot[maxn]={0};
int n;
void inorder(int root){
if(root==-1)return;
int a=Node[root].lchild,b=Node[root].rchild;
if(Node[a].lchild>=1||Node[a].rchild>=1)printf("(");
inorder(Node[root].lchild);
if(Node[a].lchild>=1||Node[a].rchild>=1)printf(")");
cout<<Node[root].str;
if(Node[b].lchild>=1||Node[b].rchild>=1)printf("(");
inorder(Node[root].rchild);
if(Node[b].lchild>=1||Node[b].rchild>=1)printf(")");
}
int main()
{
// freopen("input.txt","r",stdin);
scanf("%d",&n);
for(int i=1;i<=n;i++){
cin>>Node[i].str>>Node[i].lchild>>Node[i].rchild;
if(Node[i].lchild!=-1)isroot[Node[i].lchild]=1;
if(Node[i].rchild!=-1)isroot[Node[i].rchild]=1;
}
int root;
for(int i=1;i<=n;i++){
if(isroot[i]==0){
root=i;
break;
}
}
inorder(root);
return 0;
}
主要是输出括号比较麻烦,分别判断左右子树是否只有一个节点,如果大于1,在遍历前后输出括号。不知道为什么写!=-1不对
A1086 同1020 用栈输入
#include<iostream>
#include<stdio.h>
#include<stack>
#include<string>
using namespace std;
struct node{
int data;
node* lchild;
node* rchild;
};
int pre[40],in[40],post[40];
stack<int>s;
node* Create(int preL,int preR,int inL,int inR){
if(preL>preR){
return NULL;
}
node* root=new node;
root->data=pre[preL];
int k;
for(k=inL;k<=inR;k++){
if(in[k]==pre[preL]){
break;
}
}
int numleft=k-inL;
root->lchild=Create(preL+1,preL+numleft,inL,inL+numleft-1);
root->rchild=Create(preL+numleft+1,preR,k+1,inR); //这里的多一少一引发了全部段错误
return root;
}
int k=0,n;
void postorder(node* root){
if(root==NULL){
return;
}
postorder(root->lchild);
postorder(root->rchild);
printf("%d",root->data);
k++;
if(k<n)printf(" ");
}
int main()
{
int data1,i1=0,i2=0;
scanf("%d",&n);
string str;
for(int i=0;i<2*n;i++){
cin>>str;
if(str=="Push"){
cin>>data1;
s.push(data1);
pre[i1]=data1;
i1++;
//这里入栈顺序没有问题
}
else{
in[i2]=s.top();
i2++;
s.pop();
}
}
node* root=Create(0,n-1,0,n-1);
postorder(root);
return 0;
}
简单题,只不过换成了用栈输入。
A1102 静态二叉树遍历
#include<stdio.h>
#include<queue>
#include<iostream>
using namespace std;
const int maxn=12;
struct node{
int lchild,rchild;
}Node[maxn];
int num=0;
int n;
int isroot[maxn]={0};
void Layerorder(int root){
queue<int>q;
q.push(root);
while(!q.empty()){
int now=q.front();
q.pop();
printf("%d",now);
num++;
if(num!=n)printf(" ");
if(Node[now].lchild!=-1)q.push(Node[now].lchild);
if(Node[now].rchild!=-1)q.push(Node[now].rchild);
}
}
void inorder(int root){
if(root==-1){
return;
}
inorder(Node[root].lchild);
printf("%d",root);
num++;
if(num!=n)printf(" ");
inorder(Node[root].rchild);
}
int main()
{
for(int i=0;i<maxn;i++){
Node[i].lchild=Node[i].rchild=-1;
}
char a,b;
scanf("%d",&n);
for(int i=0;i<n;i++){
cin>>a>>b;
if(a!='-'){
Node[i].rchild=a-'0';
isroot[a-'0']=1;
}
if(b!='-'){
Node[i].lchild=b-'0';
isroot[b-'0']=1;
}
}
int root0=-1;
for(int i=0;i<n;i++){
if(isroot[i]==0){
root0=i;
break;
}
}
Layerorder(root0);
printf("\n");
num=0;
inorder(root0);
printf("\n");
return 0;
}
用isroot[]数组来寻找根节点
A1053 输出多条路径 难
#include<stdio.h>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn=100010;
struct node{
int data;
vector<int>children;
}child[maxn];
int n,m,s,lujing[maxn];
bool cmp(int a,int b){
return child[a].data>child[b].data;
}
void dfs(int index,int sumnode, int sum){
if(sum>s)return;
if(sum==s){
if(child[index].children.size()!=0)return;
for(int i=0;i<sumnode-1;i++){
printf("%d ",child[lujing[i]].data);
}
printf("%d\n",child[lujing[sumnode-1]].data);
return ;
}
if(sum<s){
for(int i=0;i<child[index].children.size();i++){
lujing[sumnode]=child[index].children[i];
dfs(child[index].children[i],sumnode+1,sum+child[child[index].children[i]].data);
}//这里函数的递归用错了,参数调用的有错误
}
}
int main()
{
int n2,father,child2;
scanf("%d %d %d",&n,&m,&s);
for(int i=0;i<n;i++){
scanf("%d",&child[i].data);
}
for(int i=0;i<m;i++){
scanf("%d %d",&father,&n2);
for(int j=0;j<n2;j++){
scanf("%d",&child2);
child[father].children.push_back(child2);
}
sort(child[father].children.begin(),child[father].children.end(),cmp);
}
lujing[0]=0;
dfs(0,1,child[0].data);
return 0;
}
//注意本题路径数组存储的结点的名字,而打印的是结点的data
//方法2
#include<stdio.h>
#include<algorithm>
#include<stdlib.h>
#include<vector>
using namespace std;
const int maxn=101;
struct node{
int weight;
vector<int>child;
}Node[maxn];
int n,m,s,fa,k,temp;
vector<int>temppath,path;
bool cmp(int a,int b){
return Node[a].weight>Node[b].weight;
}
void DFS(int root){
if(Node[root].child.size()==0){
// printf("*\n");
temppath.push_back(root);
// printf("&\n");
int sum=0;
for(int i=0;i<temppath.size();i++){
sum+=Node[temppath[i]].weight;
// printf("-------------%d\n",sum);
}
if(sum==s){
for(int j=0;j<temppath.size();j++){
printf("%d",Node[temppath[j]].weight);
if(j!=temppath.size()-1)printf(" ");
}
printf("\n");
// printf("9\n");
}
temppath.pop_back();
// printf("%%\n");
return;
}
temppath.push_back(root);
for(int i=0;i<Node[root].child.size();i++){
DFS(Node[root].child[i]);
}
temppath.pop_back();
}
int main()
{
// freopen("input.txt","r",stdin);
scanf("%d %d %d",&n,&m,&s);
for(int i=0;i<n;i++){
scanf("%d",&Node[i].weight);
}
for(int i=0;i<m;i++){
scanf("%d %d",&fa,&k);
for(int j=0;j<k;j++){
scanf("%d",&temp);
Node[fa].child.push_back(temp);
}
sort(Node[fa].child.begin(),Node[fa].child.end(),cmp);
}
// printf("%d\n",Node[Node[0].child[3]].weight);
DFS(0);
return 0;
}
第二种方法是根据图的Dijksta算法模板做出来的,调试了好久,刚开始计算sum的时候用编号累加的,后来sort函数在之前定义了cmp,sort里竟然忘写了。。。
sort的cmp函数也需要注意一下,挺特别的一个比较函数
A1064 构建完全二叉搜索树 难
#include<stdio.h>
#include<algorithm>
using namespace std;
const int maxn=1010;
int n,in[maxn],a[maxn],num=1;
void inorder(int root){
if(root>n){
return;
}
inorder(root*2);
in[root]=a[num++];
inorder(root*2+1);
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
sort(a+1,a+1+n);
inorder(1);
for(int i=1;i<=n;i++){
printf("%d",in[i]);
if(i!=n)printf(" ");
}
return 0;
}
完全二叉树一般都用数组来存储,二叉搜索树的中序遍历有顺序的
A1043 二茬搜索树 镜像遍历 简单
#include<stdio.h>
#include<vector>
using namespace std;
vector<int> temp,pre,prem,post,postm;
struct node{
int data;
node* lchild,*rchild;
};
void insert(node* &root,int x){
if(root==NULL){
root=new node;
root->data=x;
root->lchild=root->rchild=NULL;
return;
}
if(x<root->data){
insert(root->lchild,x);
}
else if(x>=root->data) {
insert(root->rchild,x);
}
}
void preorder(node* root){
if(root==NULL)return;
pre.push_back(root->data);
preorder(root->lchild);
preorder(root->rchild);
}
void premorder(node* root){
if(root==NULL)return;
prem.push_back(root->data);
premorder(root->rchild);
premorder(root->lchild);
}
void postorder(node* root){
if(root==NULL)return;
postorder(root->lchild);
postorder(root->rchild);
post.push_back(root->data);
}
void postmorder(node* root){
if(root==NULL)return ;
postmorder(root->rchild);
postmorder(root->lchild);
postm.push_back(root->data);
}
int main()
{
int n,tempchild;
scanf("%d",&n);
node* root=NULL;
for(int i=0;i<n;i++){
scanf("%d",&tempchild);
temp.push_back(tempchild);
insert(root,tempchild);
}
preorder(root);
premorder(root);
postorder(root);
postmorder(root);
if(temp==pre){
printf("YES\n");
for(int i=0;i<post.size();i++){
printf("%d",post[i]);
if(i<post.size()-1)printf(" ");
}
}else if(temp==prem){
printf("YES\n");
for(int i=0;i<postm.size();i++){
printf("%d",postm[i]);
if(i<postm.size()-1)printf(" ");
}
}
else {
printf("NO\n");
}
return 0;
}
四种遍历各来一遍,都是树的基本操作
A1099 构建二叉搜索树 同1064
#include<stdio.h>
#include<queue>
#include<algorithm>
using namespace std;
const int maxn=110;
int n,in[maxn],num=0;
struct node{
int data,lchild,rchild;
}Node[maxn];
void inorder(int root){
if(root==-1)return;
inorder(Node[root].lchild);
Node[root].data=in[num++];
inorder(Node[root].rchild);
}
void Layerorder(int root){
queue<int>q;
q.push(root);
num=0;
while(!q.empty()){
int now=q.front();
q.pop();
printf("%d",Node[now].data);
num++;
if(num<n)printf(" ");
if(Node[now].lchild!=-1)q.push(Node[now].lchild);
if(Node[now].rchild!=-1)q.push(Node[now].rchild);
}
}
int main()
{
scanf("%d",&n);
int lchild,rchild;
for(int i=0;i<n;i++){
scanf("%d%d",&lchild,&rchild);
Node[i].lchild=lchild;
Node[i].rchild=rchild;
}
for(int i=0;i<n;i++){
scanf("%d",&in[i]);
}
sort(in,in+n);
inorder(0);
Layerorder(0);
return 0;
}
只把中序遍历模板稍微改一下就可以了
A1127 构树 调换位置输出
#include<stdio.h>
#include<algorithm>
#include<queue>
#include<stdlib.h>
#include<vector>
using namespace std;
const int maxn=50;
struct node{
int data,layer0;
node* lchild;
node* rchild;
};
int n,in[maxn],post[maxn];
int maxlayer=0;
int layer[maxn]={0};
vector<int>v;
node* Create(int inl,int inr,int postl,int postr){
if(postl>postr)return NULL;
node* root=new node;
root->data=post[postr];
root->lchild=root->rchild=NULL;
int k=0;
while(in[k]!=post[postr])k++;
int numleft=k-inl;
root->lchild=Create(inl,k-1,postl,postl+numleft-1);
root->rchild=Create(k+1,inr,postl+numleft,postr-1);
return root;
}
void layerorder(node* root){
queue<node*>q;
root->layer0=1;
q.push(root);
while(!q.empty()){
node* now=q.front();
q.pop();
v.push_back(now->data);
layer[now->layer0]++;
maxlayer=max(maxlayer,now->layer0);
if(now->lchild!=NULL){
now->lchild->layer0=now->layer0+1;
q.push(now->lchild);
}
if(now->rchild!=NULL){
now->rchild->layer0=now->layer0+1;
q.push(now->rchild);
}
}
}
int main()
{
// freopen("input.txt","r",stdin);
scanf("%d",&n);
for(int i=0;i<n;i++)scanf("%d",&in[i]);
for(int i=0;i<n;i++)scanf("%d",&post[i]);
node* root=Create(0,n-1,0,n-1);
layerorder(root);
int sum=0;
for(int i=1;i<=maxlayer;i=i+2){
reverse(v.begin()+sum,v.begin()+sum+layer[i]);
sum+=layer[i]+layer[i+1];
} //调换位置
for(int i=0;i<v.size();i++){
printf("%d",v[i]);
if(i!=v.size()-1)printf(" ");
}
return 0;
}
按层序遍历的顺序把数存到数组中,并记录每层节点的个数和最大深度,最后把数组的数用reverse调换位置,输出
A1115 数后两层节点
#include <iostream>
#include <vector>
using namespace std;
struct node {
int v;
struct node *left, *right;
};
node* build(node *root, int v) {
if(root == NULL) {
root = new node();
root->v = v;
root->left = root->right = NULL;
} else if(v <= root->v)
root->left = build(root->left, v);
else
root->right = build(root->right, v);
return root;
}
vector<int> num(1000);
int maxdepth = -1;
void dfs(node *root, int depth) {
if(root == NULL) {
maxdepth = max(depth, maxdepth);
return ;
}
num[depth]++;
dfs(root->left, depth + 1);
dfs(root->right, depth + 1);
}
int main() {
int n, t;
scanf("%d", &n);
node *root = NULL;
for(int i = 0; i < n; i++) {
scanf("%d", &t);
root = build(root, t);
}
dfs(root, 0);
printf("%d + %d = %d", num[maxdepth-1], num[maxdepth-2], num[maxdepth-1] + num[maxdepth-2]);
return 0;
}
A1138
A1110 判断完全二叉树 中等题
#include<stdio.h>
#include<string>
#include<iostream>
#include<algorithm>
using namespace std;
struct node{
int lchild,rchild;
}Node[50];
int isroot[50]={0};
int n;
int maxid=-1,finmax;
string a,b;int child1,child2;
int getid(string a){
if(a=="-")return -1;
else return stoi(a);
}
void DFS(int root,int index){
// if(index>maxid){
// maxid=index;
// finmax=root;
// }
// if(Node[root].lchild!=-1)DFS(Node[root].lchild,index*2);
// if(Node[root].rchild!=-1)DFS(Node[root].rchild,index*2+1);
if(root==-1)return;
if(index>maxid){
maxid=index;
finmax=root;
}
DFS(Node[root].lchild,index*2);
DFS(Node[root].rchild,index*2+1);
}
int main()
{
cin>>n;
for(int i=0;i<n;i++){
cin>>a>>b;
child1=getid(a);
child2=getid(b);
isroot[child1]++;
isroot[child2]++;
Node[i].lchild=child1;
Node[i].rchild=child2;
}
int root=-1;
for(int i=0;i<n;i++){
if(isroot[i]==0){
root=i;
break;
}
}
DFS(root,1);
if(maxid==n)printf("YES %d\n",finmax);
else printf("NO %d\n",root);
return 0;
}
DFS函数里加入编号
A1143
A1151
A1107 课程团体 并查集
```c++
#include<stdio.h>
#include<algorithm>
using namespace std;
const int maxn=1010;
int n,k,h;
int father[maxn],isroot[maxn]={0},course[maxn]={0};
int findfather(int a){
if(father[a]==a)return a;
else{
int F=findfather(father[a]);
father[a]=F;
return F;
}
}
void Union(int a,int b){
int A=findfather(a);
int B=findfather(b);
if(A!=B){
father[B]=father[A];
}
}
bool cmp(int a,int b){
return a>b;
}
int main()
{
scanf("%d",&n);
for(int i=0;i<=n;i++){
father[i]=i;
}
for(int i=1;i<=n;i++){
scanf("%d:",&k);
for(int j=0;j<k;j++){
scanf("%d",&h);
if(course[h]==0)course[h]=i;
Union(course[h],i);
}
}
for(int i=1;i<=n;i++){
isroot[findfather(i)]++;
}
sort(isroot+1,isroot+n+1,cmp);
int cnt=0;
for(int i=1;i<=n;i++){
if(isroot[i]!=0)cnt++;
}
printf("%d\n",cnt);
for(int i=1;i<=cnt;i++){
printf("%d",isroot[i]);
if(i!=cnt)printf(" ");
else printf("\n");
}
return 0;
}
```
难点:要把课程和第一个人对应起来作为根节点建立并查集,数团体的方法要记住,遍历每一个人找父亲节点并加1,,一举两得。
易错点:由于开始时course数组初始化为0,所以在主函数输入时人名不能从0开始。也可使用map代替course数组
A1118 鸟 基础并查集
```c++
#include<stdio.h>
int n,k,h;
const int maxn=10010;
int father[maxn],isroot[maxn]={0},max=0;
int findfather(int v){
if(v==father[v])return v;
else{
int F=findfather(father[v]);
father[v]=F;
return F;
}
}
void Union(int a,int b){
int fA=findfather(a);
int fB=findfather(b);
if(fA!=fB){
father[fA]=fB;
}
return;
}
int main()
{
for(int i=0;i<maxn;i++){
father[i]=i;
}
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d",&k);
int temp;
scanf("%d",&temp);
if(temp>max)max=temp;
for(int j=1;j<k;j++){
scanf("%d",&h);
if(h>max)max=h;
Union(temp,h);
}
}
for(int i=1;i<=max;i++){
isroot[findfather(i)]++;
}
int cnt=0;
for(int i=0;i<maxn;i++){
if(isroot[i]!=0)cnt++;
}
printf("%d %d\n",cnt,max);
int n2,a,b;
scanf("%d",&n2);
for(int i=0;i<n2;i++){
scanf("%d %d",&a,&b);
if(findfather(a)==findfather(b))printf("Yes\n");
else printf("No\n");
}
return 0;
}
```
注意审题系列
> It is guaranteed that the birds in all the pictures are numbered continuously from 1 to some number that is no more than 10^4
A1034 犯罪团伙 难
暂时是用图做的,还不会并查集的做法,感觉并查集应该更麻烦,以后会了再更新
```c++
#include<stdio.h>
#include<iostream>
#include<string>
#include<map>
#include<algorithm>
using namespace std;
const int maxn=2020;
int m,s;
string a,b;int child1,child2,c;
int G[maxn][maxn]={0};
int weight[maxn]={0};
int vis[maxn]={0};
map<string,int>strtoint;
map<int,string>inttostr;
map<string,int>Gangtoint;
int finid=-1,maxweight=-1,finsum=0,finsumper=0;
int index=1;
int getid(string a){
if(strtoint[a]==0){
strtoint[a]=index;
inttostr[index]=a;
return index++;
}else{
return strtoint[a];
}
}
void DFS(int u){
if(weight[u]>maxweight){
maxweight=weight[u];
finid=u;
}
vis[u]=1;
finsumper++;
for(int v=1;v<index;v++){
if(G[u][v]!=0){
finsum+=G[u][v];
G[u][v]=G[v][u]=0;
if(vis[v]==0){
DFS(v);
}
}
}
}
void DFSTrave(){
for(int i=1;i<index;i++){
if(vis[i]==0){
finid=-1,maxweight=-1,finsum=0,finsumper=0;
DFS(i);
if(finsumper>2&&finsum>s){
Gangtoint[inttostr[finid]]=finsumper;
}
}
}
}
int main()
{
cin>>m>>s;
for(int i=0;i<m;i++){
cin>>a>>b>>c;
child1=getid(a);
child2=getid(b);
G[child1][child2]+=c;
G[child2][child1]+=c;
weight[child1]+=c;
weight[child2]+=c;
}
DFSTrave();
cout<<Gangtoint.size()<<endl;
for(auto it=Gangtoint.begin();it!=Gangtoint.end();it++){
cout<<it->first<<" "<<it->second<<endl;
}
return 0;
}
```
```
简单最短路径题 第二标准是花费,跟路径一样,注意初始化的时候也与路径一样为INF,在定义变量前想好变量名,别重复
在走完一条路径后要把路径删掉,还原到初始化状态,(要删两条边,跟输入时一样)
巨大坑点测试点2:题中两个人之间可能不止打一次电话,所以输入构建图的时候必须是加,图的初始化必须是0
A1114 家庭房产 难 已做
明天11月13日必更新此题的并查集解法
好难,写了快俩小时了还是不会,感觉自己太浮躁,写的代码逻辑混乱,各种变量写着写着就晕了,看来得规范一下格式,先把做题步骤清晰写出来,在开始敲代码。明天在更新这题吧,还是看动漫要紧。。
#include<stdio.h>
#include<stdlib.h>
#include<algorithm>
using namespace std;
const int maxn=10001;
int n,m;
int father[maxn],vis[maxn]={0};
struct node1{
int id,fa,ma,child[10];
double cnt1,area1;
}per[1001];
struct node2{
int minid,numpeople,flag;
double cnt2,area2;
}family[maxn];
int findfather(int v){
if(father[v]==v)return v;
else{
int F=findfather(father[v]);
father[v]=F;
return F;
}
}
void Union(int a,int b){
int FA=findfather(a);
int FB=findfather(b);
if(FA<FB)father[FB]=FA;
else if(FA>FB)father[FA]=FB;
}
bool cmp(node2 a,node2 b){
if(a.flag!=b.flag)return a.flag>b.flag;
else if(a.area2!=b.area2)return a.area2>b.area2;
else return a.minid<b.minid;
}
int main()
{
// freopen("input.txt","r",stdin);
for(int i=0;i<maxn;i++){
family[i].numpeople=family[i].flag=0;
family[i].cnt2=family[i].area2=0.0;
father[i]=i;
}
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d %d %d %d",&per[i].id,&per[i].fa,&per[i].ma,&m);
vis[per[i].id]=1;
if(per[i].fa!=-1){ //写错数,写成1了
Union(per[i].id,per[i].fa);
vis[per[i].fa]=1;
}
if(per[i].ma!=-1){
Union(per[i].id,per[i].ma);
vis[per[i].ma]=1;
}
for(int j=0;j<m;j++){
scanf("%d",&per[i].child[j]);
Union(per[i].id,per[i].child[j]);
vis[per[i].child[j]]=1;
}
scanf("%lf %lf",&per[i].cnt1,&per[i].area1);
}
for(int i=0;i<n;i++){
int f=findfather(per[i].id);
family[f].minid=f;
family[f].cnt2+=per[i].cnt1;
family[f].area2+=per[i].area1;
family[f].flag=1;
}
int cnt=0;
for(int i=0;i<maxn;i++){
if(vis[i]==1){
int f=findfather(i);
family[f].numpeople++;
}
if(family[i].flag)cnt++;
}
for(int i=0;i<maxn;i++){
if(family[i].flag==1){
family[i].cnt2=family[i].cnt2*(1.0)/(family[i].numpeople*1.0);
family[i].area2=family[i].area2*1.0/(family[i].numpeople*1.0);
}
}
sort(family,family+maxn,cmp);
printf("%d\n",cnt);
for(int i=0;i<cnt;i++){
printf("%04d %d %.3lf %.3lf\n",family[i].minid,family[i].numpeople,family[i].cnt2,family[i].area2);
}
return 0;
}
//8888的祖先莫名变成0
看的柳神的代码,仿照着写出来的。
两个结构体,一个用来读输入,一个用来存储家庭,vis数组用来标记是否是人,在并查集合并操作中直接让最小值作为根节点,非常巧妙的做法。家庭成员个数,和家庭数最后单独处理