前置知识
树的结构:[[2链表、邻接表]]
并查集:[[4并查集]]
#根据前序中序得后序
#二叉搜索树的中序遍历是递增的。
#完全二叉树用一维数组表示
树
1、叶节点数量✔
// #include<iostream>
// #include<vector>
// #include<map>
// using namespace std;
// struct node{
// int weight;
// vector<int> child; //指针域;
// };
// vector<int> ans(100,0);
// int max_level=0;
// void BFS(int root,int level,vector<node> nodes){
// if (level>max_level) max_level=level;
// if(nodes[root].child.size()==0) ans[level]+=1;
// else{
// for(auto it=nodes[root].child.begin();it!=nodes[root].child.end();it++){
// BFS(*it,level+1,nodes);
// }
// }
// }
// int main()
// {
// int n,m;
// cin>>n>>m;
// if(n==0) {
// cout<<1;
// return 0;
// }
// int max_level=1;
// map<string,int> level;
// vector<int> leaf_node_num(100,0);
// level["01"]=1;
// leaf_node_num[1]=1;
// for(int i=0;i<m;i++){
// string x;
// int k;
// cin>>x>>k;
// leaf_node_num[ level[x] ]-=1;
// for(int j=0;j<k;j++){
// string x_son;
// cin>>x_son;
// level[x_son]=level[x]+1;
// if(level[x_son]>max_level) max_level=level[x_son];
// leaf_node_num[ level[x_son] ]+=1;
// }
// }
// for(int i=1;i<=max_level;i++){
// cout<<leaf_node_num[i];
// if(i!=max_level) cout<<" ";
// }
// int n,m;
// cin>>n>>m;
// vector<node> nodes(n+1);
// for(int i=0;i<m;i++){
// int x,k;
// cin>>x>>k;
// for(int j=0;j<k;j++){
// int x_son;
// cin>>x_son;
// nodes[x].child.push_back(x_son);
// }
// }
// BFS(1,1,nodes);
// for(int i=1;i<=max_level;i++){
// cout<<ans[i];
// if(i!=max_level) cout<<" ";
// }
// }
#include<iostream>
#include<queue>
#include<vector>
#include<cstring>
using namespace std;
const int N = 100+10,M=2*N;
int head[N];
int val[N],ne[N];
int idx=0;
void add(int a,int b){
val[idx] = b;
ne[idx] = head[a];
head[a] = idx++;
}
vector<int> ans;
queue<int> Q;
int visited[N];
void bfs(){
Q.push(1);
while(!Q.empty()){
int n = Q.size();
int cnt=0;
while(n--){
int v = Q.front();Q.pop();
if (head[v]==-1) cnt++;
for(int idxx = head[v]; idxx !=-1; idxx =ne[idxx]){
int v = val[idxx];
if(!visited[v ]) Q.push(v),visited[v]=1;
}
}
ans.push_back(cnt);
}
}
int main(){
memset(head,-1,sizeof head);
int n,m;
cin>>n>>m;
for(int i=0;i<m;i++){
int a,k;
cin>>a>>k;
while(k--){
int b;
cin>>b;
add(a,b);
}
}
bfs();
for(int i=0;i<ans.size();i++){
if(i==ans.size()-1) cout<<ans[i]<<endl;
else cout<<ans[i]<<" ";
}
}
2、树的遍历✔
根据后续和中序建树,并输出层序遍历。 #根据前序中序得后序 这个是建树
1020 Tree Traversals
#include<iostream>
#include<unordered_map>
#include<cstring>
#include<queue>
using namespace std;
const int N = 40;
int post[N],in[N];
unordered_map<int,int> pos;
int head[N*N],val[N*N],ne[N*N];
int idx=0;
void add(int a,int b){
val[idx] = b;
ne[idx] = head[a];
head[a] =idx;
idx ++;
}
int build(int pl,int pr,int il,int ir){
int root = post[pr];int mid = pos[root];
if(mid <ir ) add(root,build(pl+(mid-1-il)+1,pr-1,mid+1,ir));
if(mid > il ) add(root,build(pl,pl+mid-1-il,il,mid-1));
return root;
}
queue<int> Q;
void bfs(int root){
Q.push(root);cout<<root;
while(!Q.empty()){
int v = Q.front();Q.pop();
for(int idxx = head[v];idxx != -1;idxx = ne[idxx]){
int child = val[idxx];
cout<<" "<<child;
Q.push(child);
}
}
}
int main(){
memset(head,-1,sizeof head);
int n;
cin>>n;
for(int i =0;i<n;i++){
cin>>post[i];
}
for(int i=0;i<n;i++){
cin>>in[i];
pos[in[i]] = i;
}
build(0,n-1,0,n-1);
bfs(post[n-1]);
cout<<endl;
}
3、有向无环图的最深的根⭐
先判断连通性—并查集;也可以用dfs。 #并查集
已知连通,判断是否是树-----n个节点的树最多有n-1条边
最后暴力枚举每个节点进行dfs求深度。
1021 Deepest Root
#include<iostream>
#include<cstring>
#include<vector>
using namespace std;
const int N = 1e4+10,M=2*N;
int p[N];
int head[N],val[M],ne[M];
int idx=0;
void add(int a,int b){
val[idx] = b;
ne[idx] =head[a];
head[a] = idx++;
}
int find(int x){
if(p[x]!=x) p[x]=find(p[x]);
return p[x];
}
int visited[N];
int dfs(int v){
int depth=0;
visited[v]=1;
for(int idxx=head[v];idxx!=-1;idxx=ne[idxx]){
int child = val[idxx];
if(!visited[child])
depth = max(depth,dfs(child) +1);
}
return depth;
}
int main (){
memset(head,-1, sizeof head);
int n;cin>>n;int k=n;
for(int i=1;i<=n;i++) p[i]=i;
for(int i=0;i<n-1;i++){
int a,b;cin>>a>>b;
add(a,b);add(b,a);
if(find(a)!=find(b))
p[find(a)]=find(b),
k--;
}
if(k>1) cout<<"Error: "<<k<<" components";
else{
int max_depth =-1;
vector<int> ans;
for(int v=1;v<=n;v++){
int depth =dfs(v);
memset(visited,0,sizeof visited);
if(depth > max_depth) max_depth =depth,ans.clear(),ans.push_back(v);
else if(depth == max_depth) ans.push_back(v);
}
for(auto &node:ans){
cout<<node<<endl;
}
}
}
4、判断二叉搜索树⭐
题目:给前序遍历,判断是否是二叉搜索树,并输出后序遍历。
这个得到后序遍历的结果的太牛了。
post[cnt++]=root;
1043 Is It a Binary Search Tree #二叉搜索树的中序遍历是递增的。 #根据前序中序得后序
#include<iostream>
#include<cstring>
#include<vector>
using namespace std;
const int N = 1000+10,M=2*N;
int pre[N],post[N],cnt;
bool isbin(int begin,int end){
if(end < begin) return true;
int root = pre[begin];
int i=begin+1;
for(;i<=end;i++){
if(pre[i]>=root) break;
}
int le=i-1;
int rb=i;
for(;i<=end;i++){
if(pre[i]<root) return false;
}
int ans = true;
if(!isbin(begin+1,le) ) ans=false;
if(!isbin(rb,end) ) ans = false;
post[cnt++] = root;
return ans ;
}
bool ismir(int begin,int end){
if(end<begin) return true;
int root = pre[begin];
int i=begin+1;
for(;i<=end;i++){
if(pre[i]<root) break;
}
int le=i-1;
int rb=i;
for(;i<=end;i++){
if(pre[i]>=root) return false;
}
int ans = true;
if(!ismir(begin+1,le) ) ans=false;
if(!ismir(rb,end) ) ans = false;
post[cnt++] = root;
return ans ;
}
int main(){
int n;cin>>n;
for(int i=0;i<n;i++){
cin>>pre[i];
}
if(isbin(0,n-1)) {
cout<<"YES"<<endl;
cout<<post[0];
for(int i=1;i<n;i++){
cout<<" "<<post[i];
}
}
else if( cnt=0,ismir(0,n-1) ){
cout<<"YES"<<endl;
cout<<post[0];
for(int i=1;i<n;i++){
cout<<" "<<post[i];
}
}
else cout<<"NO"<<endl;
}
5、完全二叉搜索树✔
中序遍历一下,递增的把点填进树里就行。
1064 Complete Binary Search Tree #完全二叉树用一维数组表示
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 1000+10;
int tree[N],order[N],cnt;
int n;
void solve(int v){
if(2*v<=n) solve(2*v);
tree[v] = order[cnt++];
if(2*v+1<=n) solve(2*v+1);
}
int main(){
cin>>n;
for(int i=0;i<n;i++){
cin>>order[i];
}
sort(order,order+n);
solve(1);
cout<<tree[1];
for(int i=2;i<=n;i++){
cout<<" "<<tree[i];
}
cout<<endl;
}
6、非递归后序遍历✔
a.一般是改堆栈方式:如果右孩子没有被访问过或者没有右孩子,则出栈并输出。145. 二叉树的后序遍历
b.这题的堆栈方式给定了,可以等到先序和中序,可再推后序。(柳佬也是这么做的,背模板的话应该也不是太耗时间吧?)
c.或者用y总的方式。
1086 Tree Traversals Again #根据前序中序得后序
7、给顶结构的二叉搜索树✔
与第5题类似
1099 Build A Binary Search Tree #二叉搜索树的中序遍历是递增的。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int N = 100+10,M = 2*N;
int inorder[N],cnt;
int l[N],r[N];
int tree[N];
void dfs(int v){
if(l[v]!=-1) dfs(l[v]);
tree[v] = inorder[cnt++];
if(r[v]!=-1) dfs(r[v]);
}
queue<int> Q;
void bfs(int root){
Q.push(root);cout<<tree[root];
while(!Q.empty()){
int v=Q.front();Q.pop();
if(l[v]!=-1){Q.push(l[v]);cout<<" "<<tree[l[v]];}
if(r[v]!=-1){Q.push(r[v]);cout<<" "<<tree[r[v]];}
}
}
int main(){
int n;cin>>n;
for(int i=0;i<n;i++){
cin>>l[i]>>r[i];
}
for(int i=0;i<n;i++){
cin>>inorder[i];
}
sort(inorder,inorder+n);
dfs(0);
bfs(0);
cout<<endl;
}
8、反转二叉树✔
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int N = 30;
int l[N],r[N];
int tree[N];
int inorder[N],cnt;
int isroot[N];
queue<int> Q;
void bfs(int root){
Q.push(root);cout<<root;
while(!Q.empty()){
int v = Q.front();Q.pop();
if(l[v]!=-1) Q.push(l[v]),cout<<" "<<l[v];
if(r[v]!=-1) Q.push(r[v]),cout<<" "<<r[v];
}
}
void dfs(int v){
if(l[v]!=-1) dfs(l[v]);
inorder[cnt++]=v;
if(r[v]!=-1) dfs(r[v]);
}
int main(){
int n;
cin>>n;
for(int i=0;i<n;i++){
string a,b;
cin>>a>>b;
if(a[0]=='-') r[i]=-1;
else r[i]=a[0]-'0',isroot[r[i]] = 1;
if(b[0]=='-') l[i]=-1;
else l[i]=b[0]-'0',isroot[l[i]] = 1;
}
int root;
for(int i=0;i<n;i++) {
if(isroot[i]==0) root =i;}
bfs(root);
cout<<endl;
dfs(root);
cout<<inorder[0];
for(int i=1;i<n;i++){
cout<<" "<<inorder[i];
}
cout<<endl;
}
9、判断完全二叉树✔
数据读入有问题处理了2个小时,人麻了。
因为第8题的n是小于10的,lc[0]不能读2位数。
1110 Complete Binary Tree #完全二叉树用一维数组表示
#include<iostream>
#include<cstring>
using namespace std;
const int N = 20;
int l[N],r[N];
int isroot[N];
int tree[N];
int main(){
int n;cin>>n;
memset(l, -1, sizeof l);
memset(r, -1, sizeof r);
string ls, rs;
for (int i = 0; i < n; i++) {
cin >> ls >> rs;
if (ls != "-") {
l[i] = stoi(ls);
isroot[l[i]] = 1;
}
if (rs != "-") {
r[i] = stoi(rs);
isroot[r[i]] = 1;
}
}
int root=0;
for(int i=0;i<n;i++){
if(isroot[i]==0) root=i;
}
memset(tree,-1,sizeof tree);
tree[1]=root;
int cnt=0;
for(int i=1;i<=n;i++){
if(tree[i]==-1) continue;
tree[2*i] = l[tree[i]];
tree[2*i+1] = r[tree[i]];
cnt++;
}
if(cnt==n) cout<<"YES "<<tree[n]<<endl;
else cout<<"NO "<<root<<endl;
}
10、二叉搜索树的插入✔
1115 Counting Nodes in a Binary Search Tree
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int N = 1000+10;
int l[N], r[N],val[N];
int cnt;
int high[N];
void insert(int i,int root){
if(val[i]<=val[root]) {
if(l[root]==-1) l[root]=i;
else insert(i,l[root]);
}
if(val[i]>val[root] ){
if(r[root]==-1) r[root]=i;
else insert(i,r[root]);
}
}
queue<int> Q;
void bfs(int root){
Q.push(root);
while(!Q.empty()){
int n = Q.size();
for(int i=0;i<n;i++){
int v= Q.front();Q.pop();
high[cnt]++;
if(l[v]!=-1) Q.push(l[v]);
if(r[v]!=-1) Q.push(r[v]);
}
cnt++;
}
}
int main(){
int n;cin>>n;
memset(l,-1,sizeof l);
memset(r,-1,sizeof r);
for(int i=0;i<n;i++) cin>>val[i];//insert(i,0);
for(int i=1;i<n;i++) insert(i,0);
bfs(0);
cout<<high[cnt-1]<<" + "<<high[cnt-2]<<" = "<<high[cnt-1]+high[cnt-2];
}
11、前序后序得中序✔
y总是暴力枚举的,我觉得不太行。
按我的来吧
1119 Pre- and Post-order Traversals #根据前序中序得后序
#include<iostream>
#include<cstring>
using namespace std;
const int N = 40;
int pre[N],post[N];
int pos[N];
int inorder[N],idx;
int dfs(int l1,int r1,int l2,int r2){
if(l1 > r1 ) return 1;
if(l1==r1) {
inorder[idx++]=pre[l1];
return 1;
}
int flag=0;
if(pre[l1+1]==post[r2-1]) flag=1;
int cnt = 0;
int length = pos[pre[l1+1]] -l2 +1;
int lcnt = dfs(l1+1,l1+1+length-1,l2,l2+length-1);
inorder[idx++]=pre[l1];
int rcnt =dfs(l1+1+length,r1,l1+1+length-r1+r2-1,r2-1);
cnt = lcnt*rcnt;
if(flag==1) cnt=2*cnt;
return cnt;
}
int main(){
int n;cin>>n;
for(int i=0;i<n;i++) cin>>pre[i];
for(int i=0;i<n;i++) cin>>post[i],pos[post[i]]=i;
int cnt = dfs(0,n-1,0,n-1);
if(cnt==1) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
cout<<inorder[0];
for(int i=1;i<n;i++){
cout<<" "<<inorder[i];
}
cout<<endl;
}
12、Z型层序遍历✔
1127 ZigZagging on a Tree #根据前序中序得后序
#include<iostream>
#include<cstring>
#include<unordered_map>
#include<queue>
using namespace std;
const int N = 40;
int inorder[N],post[N];
unordered_map<int,int> l,r,pos;
int lorder[N],cnt;
int build(int il,int ir,int pl,int pr){
int root = post[pr];
int k = pos[root];
if(il<k) l[root] = build(il,k-1,pl,k-1-il+pl);
if(k<ir) r[root] = build(k+1,ir, k+1-ir+pr-1 ,pr-1);
return root;
}
queue<int> Q;
void bfs(int root){
int level=0;
Q.push(root);
while(!Q.empty()){
int n=Q.size();
for(int i=0;i<n;i++){
int v= Q.front();Q.pop();
if(level % 2== 0)
lorder[cnt+n-1-i] = v;
else lorder[cnt+i] = v;
if(l.count(v)) Q.push(l[v]);
if(r.count(v)) Q.push(r[v]);
}
cnt+=n;
level++;
}
}
int main(){
int n;cin>>n;
for(int i=0;i<n;i++) cin>>inorder[i],pos[inorder[i]]=i;
for(int i=0;i<n;i++) cin>>post[i];
int root = build(0,n-1,0,n-1);
bfs(root);
cout<<lorder[0];
for(int i=1;i<n;i++) cout<<" "<<lorder[i];
cout<<endl;
}
13、前序中序得后序第一位✔
这题主要增大了N,必须用hash存pos。
1138 Postorder Traversal #根据前序中序得后序
#include<iostream>
#include<unordered_map>
using namespace std;
const int N= 50010;
int pre[N],inorder[N];
unordered_map<int,int> l,r,pos;
int post[N],cnt;
int ans;
void build(int pl,int pr,int il,int ir){
int root = pre[pl];
int k = pos[root];
if(k > il) build( pl+1,k-1-il+pl+1 ,il,k-1);
if(k< ir) build( k+1-ir+pr,pr,k+1,ir);
// post[cnt++]=root;
if(!cnt++) ans=root;
}
int main(){
int n;cin>>n;
for(int i=0;i<n;i++) cin>>pre[i];
for(int i=0;i<n;i++) cin>>inorder[i],pos[inorder[i]]=i;
build(0,n-1,0,n-1);
// cout<<post[0]<<endl;
cout<<ans<<endl;
}
14、平衡二叉树的插入✔
y总那个太复杂了,可能我没get到吧
按我的来吧。
1066 Root of AVL Tree
#include<iostream>
//#include<algorithm>
#include<cstring>
#include<unordered_map>
using namespace std;
const int N = 30;
int l[N],r[N],val[N];
unordered_map<int,int> high;//初始化是0
void update(int u){
high[u] = max(high[l[u]],high[r[u]])+1;
}
void R(int &a){
int b = l[a];
l[a] = r[b],r[b] = a;
update(a),update(b);
a = b;
}
void L(int &a){
int b = r[a];
r[a] = l[b],l[b] = a;
update(a),update(b);
a = b;
}
int get_balance(int u){
return high[l[u]] - high[r[u]];
}
void insert(int i,int &root){
if(val[i]<val[root]){
if(l[root]==-1) l[root]=i,high[i]=1;
else insert(i,l[root]);
if(get_balance(root) ==2 ){
if(get_balance(l[root])==1) R(root);
else L(l[root]),R(root);
}
}
else{
if(r[root]==-1) r[root]=i,high[i]=1;
else insert(i,r[root]);
if(get_balance(root) ==-2 ){
if(get_balance(r[root])==-1) L(root);
else R(r[root]),L(root);
}
}
update(root);
}
int main (){
high[-1]=0;
int n;cin>>n;
memset(l,-1,sizeof l);
memset(r,-1,sizeof r);
for(int i =0;i<n;i++) cin>>val[i];
int root=0;high[0]=1;
for(int i =1;i<n;i++) insert(i,root);
cout<<val[root];
}
15、平衡二叉树的插入plus✔
AVL的插入;层序遍历;判断完全二叉树。
1123 Is It a Complete AVL Tree
#include<iostream>
#include<unordered_map>
#include<cstring>
#include<queue>
using namespace std;
const int N = 30;
int l[N],r[N],val[N];
unordered_map <int,int> high;
void update(int i){
high[i] = max(high[l[i]],high[r[i]])+1;
}
int get_balance(int u){
return high[l[u]]-high[r[u]];
}
void R(int &a){
int b = l[a];
l[a] = r[b];
r[b] = a;
update(a),update(b);
a = b;
}
void L(int &a){
int b = r[a];
r[a] = l[b];
l[b] = a;
update(a),update(b);
a = b;
}
void insert(int i,int &root){
if(val[i]<val[root]){
if(l[root]==-1) l[root]=i,high[i]=1;
else {
insert(i,l[root]);
if(get_balance(root)==2){
if(get_balance(l[root])==1) R(root);
else L(l[root]),R(root);
}
}
}
else if(val[i]>val[root]){
if(r[root]==-1) r[root]=i,high[i]=1;
else {
insert(i,r[root]);
if(get_balance(root)==-2){
if(get_balance(r[root])==-1) L(root);
else R(r[root]),L(root);
}
}
}
update(root);
}
queue<int> Q;
void bfs(int root){
Q.push(root);cout<<val[root];
while(!Q.empty()){
int v = Q.front();Q.pop();
if(l[v]!=-1) Q.push(l[v]),cout<<" "<<val[l[v]];
if(r[v]!=-1) Q.push(r[v]),cout<<" "<<val[r[v]];
}
}
int max_k;
void dfs(int i,int k){
max_k=max(max_k,k);
if(l[i]!=-1) dfs(l[i],2*k);
if(r[i]!=-1) dfs(r[i],2*k+1);
}
int main(){
high[-1]=0;
memset(l,-1,sizeof l);
memset(r,-1,sizeof r);
int n;cin>>n;
for(int i=0;i<n;i++) cin>>val[i];
int root=0;high[0]=1;
for(int i=1;i<n;i++) insert(i,root);
bfs(root);
dfs(root,1);
if(max_k>n) cout<<endl<<"NO"<<endl;
else cout<<endl<<"YES"<<endl;
}
16、判断红黑树✔
1135 Is It A Red-Black Tree #二叉搜索树的中序遍历是递增的。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<unordered_map>
using namespace std;
const int N = 40;
int pre[N],inorder[N];
unordered_map<int,int> pos,l,r;
bool ans;
bool cmp(int a,int b){
return abs(a)<abs(b);
}
int build(int pl,int pr,int il,int ir,int &sum){
//if(pl > pr) return -1;
int root = pre[pl];
int k = pos[root];
if( k <il || k>ir){
ans = false;
return 0;
}
// 给定的前序遍历非法。
// 1
// 9
// 7 -2 1 5 -4 -11 3 14 -15
int ls=0,rs=0;
if(il < k ) l[root] = build(pl+1,k-1-il+pl+1 , il,k-1,ls);
if( k < ir) r[root] = build( k+1-ir+pr ,pr,k+1,ir,rs);
if(ls!=rs) ans=false; //左右子树黑结点个数不等
sum = ls;
if(root < 0) {
if(l[root] <0 || r[root] <0) ans=false; //红色结点的孩子也是红色结点 则 非法。
}
else sum++; //黑结点个数+1
return root;
}
int main(){
int k;cin>>k;
while(k--){
l.clear();
r.clear();
pos.clear();
int n;cin>>n;
for(int i=0;i<n;i++) cin>>pre[i],inorder[i]=pre[i];
sort(inorder,inorder+n,cmp);
for(int i=0;i<n;i++) pos[inorder[i]]=i;
int sum=0;
ans = true;
int root = build(0,n-1,0,n-1,sum);
if( ans && root>0) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
}
17、路径之和✔
每次dfs前后 对自己需要的内容进行处理,有点回溯那味了。
1053 Path of Equal Weight
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
const int N = 110;
int head[N],val[N],ne[N],idx=0;
int w[N];
int tag;
vector<int> path;
vector< vector <int> > ans;
int sum=0;
void add(int a,int b){
val[idx] = b;
ne[idx] = head[a];
head[a] = idx++;
}
void dfs(int root){
path.push_back(w[root]);sum+=w[root];
if(sum==tag && head[root]==-1 ) ans.push_back(path);
for(int idxx=head[root];idxx!=-1;idxx=ne[idxx]){
dfs(val[idxx]);
}
path.pop_back();
sum-=w[root];
}
int main(){
memset(head,-1,sizeof head);
int n,m;
cin>>n>>m>>tag;
for(int i=0;i<n;i++) cin>>w[i];
for(int i=0;i<m;i++){
int v;cin>>v;
int k;cin>>k;
while(k--){
int b;cin>>b;
add(v,b);
}
}
dfs(0);
sort(ans.begin(),ans.end());
reverse(ans.begin(),ans.end());
for(auto &v : ans){
cout<<v[0];
for(int i=1;i<v.size();i++){
cout<<" "<<v[i];
}
cout<<endl;
}
}
18、最大层数✔
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int N = 110;
int head[N],ne[N],val[N],idx=0;
void add(int a,int b){
val[idx] = b;
ne[idx] = head[a];
head[a] = idx++;
}
int max_level,max_cnt;
queue<int> Q;
void bfs(int root){
Q.push(root);
int level=0;
while(!Q.empty()){
int n=Q.size();
level++;
if(n>max_cnt) {
max_cnt =n;
max_level = level;
}
for(int i=0;i<n;i++){
int v = Q.front();Q.pop();
for(int idxx=head[v];idxx!=-1;idxx=ne[idxx]){
int child = val[idxx];
Q.push(child);
}
}
}
}
int main(){
memset(head,-1,sizeof head);
int n,m;cin>>n>>m;
while(m--){
int v,k;cin>>v>>k;
while(k--) {
int b;cin>>b;
add(v,b);
}
}
bfs(1);
cout<<max_cnt<<" "<<max_level<<endl;
}
19、供应链1✔
1079 Total Sales of Supply Chain
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int N = 1e5+10;
int head[N],val[N],ne[N],idx=0;
int sales[N];
double rate,price;
double ans=0;
void add(int a,int b){
val[idx] = b;
ne[idx] = head[a];
head[a] = idx++;
}
queue<int> Q;
void bfs(int root){
Q.push(root);
while(!Q.empty()){
int n=Q.size();
while(n--){
int v = Q.front();Q.pop();
if(sales[v]>0) ans+=sales[v]*price;//cout<<price<<" ";
for(int idxx=head[v];idxx!=-1;idxx=ne[idxx]){
int child = val[idxx];
Q.push(child);
}
}
price *= (1+rate/100);
}
}
int main(){
memset(head,-1,sizeof head);
int n;
cin>>n>>price>>rate;
for(int i=0;i<n;i++){
int k;cin>>k;
if(k>0) {
while(k--){
int b;cin>>b;add(i,b);
}
}
else cin>>sales[i];
}
bfs(0);
printf("%.1lf\n",ans);
}
20、供应链2✔
1090 Highest Price in Supply Chain
#include<iostream>
#include<cstring>
#include<queue>
#include<cmath>
using namespace std;
const int N = 1e5+10;
int head[N],val[N],ne[N],idx=0;
double price,rate;
void add(int a,int b){
val[idx] = b;
ne[idx] = head[a];
head[a] =idx++;
}
int level,cnt;
queue<int> Q;
void bfs(int root){
Q.push(root);
while(!Q.empty()){
int n=Q.size();level++;
cnt=n;
while(n--){
int v=Q.front();Q.pop();
for(int idxx=head[v];idxx!=-1;idxx=ne[idxx]){
int child = val[idxx];
Q.push(child);
}
}
}
}
int main(){
memset(head,-1,sizeof head);
int n;cin>>n>>price>>rate;
int root=-1;
for(int i=0;i<n;i++){
int a;cin>>a;
if(a!=-1) add(a,i);
else root=i;
}
bfs(root);
printf("%.2lf %d\n",price*pow((1+rate/100),level-1),cnt);
}
21、供应链3✔
1106 Lowest Price in Supply Chain
22、堆路径
23、
24、
25、
并查集
1、战争中的城市连通✔
合并的操作!!! -------> p【find(a)】=find(b)
1013 Battle Over Cities #并查集
#include<iostream>
#include<vector>
#include<map>
using namespace std;
typedef pair<int,int> PII;
const int N = 1000+10,M=N*N;
int n,m;
int d[N][N]; //距离矩阵初始化
int p[N]; //并查集
PII edge[M];
int find(int x){
if(p[x] !=x ) p[x]=find(p[x]);
return p[x];
}
void count_connect(int id){
for(int i=1;i<=n;i++) p[i]=i; //初始化
for(int i=0;i<m;i++){
int a=edge[i].first;
int b= edge[i].second;
if(a!=id && b!=id && find(a)!=find(b)) p[find(a)]=find(b);
}
int cnt=0;
for(int i=1;i<=n;i++){
if(p[i]==i) cnt++;
}
cout<<cnt-2<<endl;
}
int main()
{
int k;
cin>>n>>m>>k;
for(int i=0;i<m;i++){
int pos1,pos2;
cin>>pos1>>pos2;
edge[i].first=pos1;
edge[i].second=pos2;
} //完成距离矩阵赋值
while(k--){
int city_id;
cin>>city_id;
count_connect(city_id); //连通图,去掉这个city相关路径后,还剩的连通个数(遍历)
}
}
2、房产⭐
需要维护每个家庭的信息。
1114 Family Property #并查集
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
typedef pair <int,int> PII;
struct Family{
string id;
int cnt;
double num,area;
bool operator < (Family x){
if(area != x.area) return area>x.area;
else return id<x.id;
}
};
const int N = 10000+10,M=N*7+10;
int n;
int p[N],visited[N],people_cnt[N],estate_cnt[N],area[N],head[N];
PII edge[M];int m=0;
int find(int x){
if(x!=p[x]) p[x] = find(p[x]);
return p[x];
}
string solve(int x){
x+=10000;
return to_string(x).substr(1);
}
int main(){
for(int i=0;i<=9999;i++) p[i]=i,people_cnt[i]=1,head[i]=i;
cin>>n;
while(n--){
int id,father,mother,k;
cin>>id>>father>>mother>>k;
visited[id]=true;
if(father !=-1) edge[m++] = {id,father},visited[father]=true;
if(mother !=-1) edge[m++] = {id,mother},visited[mother]=true;
while(k--){
int child;cin>>child;
edge[m++] = {id,child};
visited[child] = true;
}
double a,b;
cin>>a>>b;
estate_cnt[id]=a;
area[id]=b;
}
for(int i=0;i<m;i++){
int a=edge[i].first;
int b=edge[i].second;
if(find(a)!=find(b)){
people_cnt[find(b)] += people_cnt[find(a)];
estate_cnt[find(b)] += estate_cnt[find(a)];
area[find(b)] += area[find(a)];
head[find(b)] = min (head[find(a)],head[find(b)]);
p[find(a)] = find(b); //这个一定要放最后
}
}
int cnt=0;
vector<Family> ans;
for(int id=0;id<=9999;id++){
if(visited[id] && p[id]==id){
cnt++;
int num = people_cnt[id];
double a = estate_cnt[id];
double b = area[id];
ans.push_back({solve(head[id]),num,a/num,b/num});
}
}
sort(ans.begin(),ans.end());
cout<<cnt<<endl;
for(auto &v:ans){
cout<<v.id<<" "<<v.cnt<<" ";
printf("%.3lf %.3lf\n",v.num,v.area);
}
}
3、树上的鸟✔
有了上题,这题就秒解了。
1118 Birds in Forest #并查集
#include<iostream>
using namespace std;
const int N = 10000+10;
int n;
int p[N];
bool visited[N];
int find(int x){
if(x!=p[x]) p[x]=find(p[x]);
return p[x];
}
int main(){
for(int i=0;i<N;i++) p[i]=i;
cin>>n;
for(int i=0;i<n;i++){
int k;cin>>k;
int first;
cin>>first;visited[first]=true;
for(int j=1;j<k;j++){
int a;cin>>a;
if(find(a)!=find(first) ){
p[find(a)] = find(first);
visited[a] = true;
}
}
}
int tree=0,bird=0;
for(int i=0;i<N;i++){
if(p[i]==i && visited[i]) tree++;
if(visited[i]) bird++;
}
cout<<tree<<" "<<bird<<endl;
int q;cin>>q;
while(q--){
int a,b;
cin>>a>>b;
if(find(a)==find(b)) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
}
4、社会集群✔
有相同爱好的人聚类到一起。
1107 Social Clusters #并查集
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
const int N = 1000+10;
int n;
int p[N],cnt[N];
vector<int> hobbys[N];
int find(int x){
if(x!=p[x]) p[x]=find(p[x]);
return p[x];
}
int main(){
cin>>n;
for(int i=1;i<=n;i++) p[i]=i,cnt[i]=1;
for(int i=1;i<=n;i++){
int k;cin>>k;
char temp;cin>>temp;
while(k--){
int hobby;cin>>hobby;
hobbys[hobby].push_back(i);
}
}
for(int i=1;i<=1000;i++){
if(!hobbys[i].empty() ){
for(int j=1;j<hobbys[i].size();j++){
if(find(hobbys[i][j])!= find(hobbys[i][0]) ){
cnt[find(hobbys[i][0])] += cnt[find(hobbys[i][j])];
p[find(hobbys[i][j])] = find( hobbys[i][0] ) ;
}
}
}
}
int ans_cnt=0;
vector<int> ans;
for(int i=1;i<=n;i++){
if(p[i]==i) ans_cnt++;
if(p[i]==i) ans.push_back(cnt[i]);
}
cout<<ans_cnt<<endl;
sort(ans.begin(),ans.end(),greater<int>());
cout<<ans[0];
for(int i=1;i<ans.size();i++) cout<<" "<<ans[i];
cout<<endl;
}