- P1087 FBI樹
- P1030 求先序排列
- P1305 新二叉樹
- P1229 遍歷問題
- P5018 對稱二叉樹
- P5597 【XR-4】復讀
- P2195 HXY造公園
- P3629 [APIO2010]巡邏
- P5536 【XR-3】核心城市
- P1099 樹網的核
- P4408 [NOI2003]逃學的小孩
1.P1087 FBI樹
遞歸求解,判斷是否爲’0’串或者’1’串即可
#include<bits/stdc++.h>
using namespace std;
string a;
int n;
void chuan(string x){
if(x.length()>0){
int len=x.length();
chuan(x.substr(0,len/2));
chuan(x.substr(len/2,len-1));
if (x == string(x.length(), '0')) cout<<'B';
else if (x == string(x.length(), '1')) cout<<'I';
else{
cout<<'F';
}
}
}
int main(){
cin>>n>>a;
chuan(a);
return 0;
}
2.P1030 求先序排列
給出了中序和後序排列,求先序排列
由這兩種輸出方式的性質可知,根在後序的最後輸出,所以我們找到根爲分界線,不斷遞歸爲兩個子樹進行求解
#include<bits/stdc++.h>
using namespace std;
string a,b;
void dfs(string x,string y){
if(x.length()>0){
int len=y.length();
cout<<y[len-1];
char ch=y[len-1];
int t=x.find(ch);
dfs(x.substr(0,t),y.substr(0,t));
dfs(x.substr(t+1,len-1),y.substr(t,len-t-1));}
}
int main(){
cin>>a>>b;
dfs(a,b);
return 0;
}
3.P1305 新二叉樹
給一棵樹,輸出先序遍歷,直接遞歸即可
#include<bits/stdc++.h>
using namespace std;
struct node{
char lc,rc;
}t[200];
char t1,tt;
void xianxu(char x){
if(x=='*') return;
cout<<x;
xianxu(t[x].lc);
xianxu(t[x].rc);
}
int main(){
int n;
cin>>n;
cin>>t1;
cin>>t[t1].lc;
cin>>t[t1].rc;
for(int i=2;i<=n;i++){
cin>>tt;
cin>>t[tt].lc;
cin>>t[tt].rc;
}
xianxu(t1);
return 0;
}
4.P1229 遍歷問題
給出先序和後序遍歷,求這棵樹最多有多少種不同中序遍歷的情況
中序+x 可以求出這棵樹
轉化一下題意就是求有多少個子樹只有一個兒子
#include<bits/stdc++.h>
using namespace std;
string a,b;
int main(){
cin>>a;
cin>>b;
int ans=0;
int n=a.length();
for(int i=0;i<n;i++){
for(int j=1;j<n;j++){
if(a[i]==b[j]&&a[i+1]==b[j-1]){
ans++;
}
}
}
printf("%d",1<<ans);
}
5.P5018 對稱二叉樹
遍歷每一個節點,遞歸判斷子樹是否對稱,並更新最大值
#include<bits/stdc++.h>
using namespace std;
#define int long long
struct node{
int l,r,w;
}t[1000005];
int n;
bool same(int x,int y){
if(x==-1&&y==-1)return true;
if(x==-1||y==-1)return false;
if(t[x].w!=t[y].w)return false;
return same(t[x].l,t[y].r)&&same(t[x].r,t[y].l);
}
int ct(int x){
return x==-1?0:ct(t[x].l)+ct(t[x].r)+1;
}
signed main(){
cin>>n;
for(int i=1;i<=n;i++){
scanf("%lld",&t[i].w);
}
for(int i=1;i<=n;i++){
scanf("%lld%lld",&t[i].l,&t[i].r);
}
int ans=0;
for(int i=1;i<=n;i++){
if(same(i,i))ans=max(ans,ct(i));
}
cout<<ans;
return 0;
}
6.P5597 【XR-4】復讀
咕咕咕待補
7.P2195 HXY造公園
操作1,輸出該點所在的樹的直徑
操作2,將u,v所在的樹連接,並且要求連接後的樹的直徑儘量小
怎麼實現操作2?選兩個直徑的中點進行合併
#include<bits/stdc++.h>
using namespace std;
const int maxn=3e5+5;
int f[maxn],c[maxn],vis[maxn],n,m,q,g[maxn],d[maxn],len;
vector<int>e[maxn];
int find(int x){
if(x==f[x])return x;
return f[x]=find(f[x]);
}
void dfs(int x,int fa){
int m1=-1,m2=-1;
for(int i=0;i<e[x].size();++i){
int y=e[x][i];
if(y==fa)continue;
dfs(y,x);
int tmp=d[y]+1;
d[x]=max(d[x],tmp);
if(tmp>m1)m2=m1,m1=tmp;
else if(tmp>m2)m2=tmp;
}
g[x]=max(max(0,m1+m2),max(m1,m2));
len=max(len,g[x]);
}
void calc(int x)
{
len=0;
dfs(x,0);
c[x]=len;
}
int main(){
cin>>n>>m>>q;
for(int i=1;i<=n;i++){
f[i]=i;
}
for(int i=1;i<=m;i++){
int u,v;
scanf("%d%d",&u,&v);
e[u].push_back(v);
e[v].push_back(u);
f[find(u)]=find(v);
}
for(int i=1;i<=n;i++){
if(f[i]!=i||vis[i])continue;
calc(i);
vis[i]=1;
}
int tt,u,v;
while(q--){
scanf("%d",&tt);
if(tt==1){
scanf("%d",&u);
printf("%d\n",c[find(u)]);
continue;
}
scanf("%d%d",&u,&v);
int x=find(u);
int y=find(v);
if(x==y)continue;
int t=((c[x]+1)/2)+((c[y]+1)/2)+1;
t=max(t,max(c[x],c[y]));
f[find(x)]=find(y);
c[find(x)]=t;
}
return 0;
}
8.P3629 [APIO2010]巡邏
有兩種情形,k=1的時候只需要找到直徑,連接兩端即可
k=2時,如果連接的邊經過了第一條路徑,就要再走一遍,所以把第一條已經連好的路上權值取負
x-y-(-y)=x
由於dfs求直徑不能處理負數,所以用dp求,也是這個題的精髓所在,需要用dfs求直徑來記錄路徑,用dp來處理負權
#include<bits/stdc++.h>
using namespace std;
const int maxm=2e5+5;
int head[maxm],dis[maxm],n,k,cnt=1,pos,st,ed;
int f[maxm],vis[maxm];
struct edge{
int v,w,nex;
}e[maxm];
inline void add(int u,int v){
e[++cnt].v=v;
e[cnt].w=1;
e[cnt].nex=head[u];
head[u]=cnt;
}
void dfs(int u,int fa){
if(dis[u]>dis[pos]||pos==st)pos=u;
f[u]=fa;
for(int i=head[u];i;i=e[i].nex){
int v=e[i].v;
if(v==fa)continue;
dis[v]=dis[u]+e[i].w;
dfs(v,u);
}
return;
}
void change(int u,int fa){
for(int i=head[u];i;i=e[i].nex){
int v=e[i].v;
if(v==fa)continue;
if(vis[v]){
e[i].w=-1;
e[i^1].w=-1;
}
change(v,u);
}
return;
}
int l2;
void dp(int u,int fa){
for(int i=head[u];i;i=e[i].nex){
int v=e[i].v;
if(v==fa)continue;
dp(v,u);
l2=max(dis[v]+dis[u]+e[i].w,l2);
dis[u]=max(dis[u],dis[v]+e[i].w);
}
return;
}
int main(){
cin>>n>>k;
int u,v;
for(int i=1;i<=n-1;i++){
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
st=1;
pos=1;
dis[1]=0;
dfs(st,0);
st=pos;
dis[st]=0;
dfs(st,0);
ed=pos;
int l1=dis[ed];
int r=ed;
while(r){
vis[r]=1;
r=f[r];
}
change(st,0);
memset(dis,0,sizeof(dis));
dp(st,0);
if(k==1)l2=1;
int ans=n*2-l1-l2;
cout<<ans;
return 0;
}
9.P5536 【XR-3】核心城市
在樹中間選一些點,使其他點到這些點的最大距離最小
先求直徑,再求中點,中點一定要被選中,然後以中點爲根建樹,進行一次dfs,統計每個點向下延伸的最大深度,對子節點進行排序,顯然第k+1個節點+1即爲答案(因爲記錄的是最大延伸,需要加上自己與核心城市的距離1)
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
int n,k,head[maxn],f[maxn],st,ed,pos,dis[maxn],cnt,vis[maxn],len[maxn];
struct edge{
int v,w,nex;
}e[maxn];
vector<int>ve;
inline void add(int u,int v){
e[++cnt].v=v;
e[cnt].w=1;
e[cnt].nex=head[u];
head[u]=cnt;
}
void dfs(int u,int fa){
if(dis[u]>dis[pos]||pos==st)pos=u;
f[u]=fa;
for(int i=head[u];i;i=e[i].nex){
int v=e[i].v;
if(v==fa)continue;
dis[v]=dis[u]+1;
dfs(v,u);
}
return;
}
void dfs3(int sn,int fa){
len[sn]=0;
for(int i=head[sn];i;i=e[i].nex){
int v=e[i].v;
if(v!=fa){
dfs3(v,sn);
len[sn]=max(len[sn],len[v]+1);
}
}
}
bool cmp(int x,int y){
return x>y;
}
int main(){
cin>>n>>k;
for(int i=1;i<=n-1;i++){
int u,v;
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
st=1,pos=1,dis[1]=0;
dfs(st,0);
st=pos,dis[st]=0;
dfs(st,0);
ed=pos;
int l1=dis[ed];
int st2=ed;
for(int i=1;i<=(l1+1)/2;i++){
st2=f[st2];
}
dfs3(st2,0);
sort(len+1,len+1+n,cmp);
cout<<len[k+1]+1;
return 0;
}
10.P1099 樹網的核
P2491 [SDOI2011]消防
U89620 樹網的核加強版
這兩題是數據加強板(三倍經驗)
前提是用最優解做的
直接上數據最強的一個版本的代碼
大體的思路是這樣的,先用dfs求出直徑,然後從端點進行遍歷,選擇每一段小於等於s的路徑,求出兩端點到這段路徑的最小距離,
然後求出每個直徑上的點到這個點的最小距離,跟ans進行比較
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
int n,s,head[maxn],f[maxn],st,ed,pos,dis[maxn],cnt,vis[maxn],len[maxn];
inline int read()
{
int x=0,k=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*k;
}
struct edge{
int v,w,nex;
}e[maxn];
inline void add(int u,int v,int w){
e[++cnt].v=v;
e[cnt].w=w;
e[cnt].nex=head[u];
head[u]=cnt;
}
void dfs(int u,int fa){
if(dis[u]>dis[pos]||pos==st)pos=u;
f[u]=fa;
for(int i=head[u];i;i=e[i].nex){
int v=e[i].v;
if(v==fa||vis[v]==1)continue;
dis[v]=dis[u]+e[i].w;
dfs(v,u);
}
return;
}
void dfs2(int u,int fa){
for(int i=head[u];i;i=e[i].nex){
int v=e[i].v;
if(v==fa||vis[v]==1)continue;
dis[v]=dis[u]+e[i].w;
dfs(v,u);
}
return;
}
int main(){
cin>>n>>s;
int u,v,w;
for(int i=1;i<=n-1;i++){
u=read(),v=read(),w=read();
add(u,v,w);
add(v,u,w);
}
st=1,pos=1,dis[1]=0;
dfs(st,0);
st=pos,dis[st]=0;
dfs(st,0);
ed=pos;
int ans=0x3f3f3f3f;
int tmp=ed;
for(int i=ed;i;i=f[i]){
while(f[tmp]&&dis[i]-dis[f[tmp]]<=s){
tmp=f[tmp];
}
ans=min(ans,max(dis[ed]-dis[i],dis[tmp]));
}
for(int i=ed;i;i=f[i]){
vis[i]=1;
dis[i]=0;
}
// cout<<ed<<endl;
// for(int i=1;i<=n;i++){
// printf("%d %d vis:%d\n",i,f[i],vis[i]);
// }
for(int i=ed;i;i=f[i]){
dfs2(i,0);
}
for(int i=1;i<=n;i++){
if(!vis[i]){
ans=max(ans,dis[i]);
}
}
cout<<ans;
return 0;
}
11.P4408 [NOI2003]逃學的小孩
求非直徑上的點到直徑的兩端點的最大值
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=4e5+5;
int dis2[maxn],dis3[maxn];
int n,m,head[maxn],f[maxn],st,ed,pos,dis[maxn],cnt,vis[maxn],len[maxn];
inline int read()
{
int x=0,k=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*k;
}
struct edge{
int v,w,nex;
}e[maxn];
inline void add(int u,int v,int w){
e[++cnt].v=v;
e[cnt].w=w;
e[cnt].nex=head[u];
head[u]=cnt;
}
void dfs(int u,int fa){
if(dis[u]>dis[pos]||pos==st)pos=u;
f[u]=fa;
for(int i=head[u];i;i=e[i].nex){
int v=e[i].v;
if(v==fa)continue;
dis[v]=dis[u]+e[i].w;
dfs(v,u);
}
return;
}
void dfs2(int u,int fa){
for(int i=head[u];i;i=e[i].nex){
int v=e[i].v;
if(v==fa||vis[v]==1)continue;
dis2[v]=dis2[u]+e[i].w;
dfs2(v,u);
}
return;
}
void dfs3(int u,int fa){
for(int i=head[u];i;i=e[i].nex){
int v=e[i].v;
if(v==fa||vis[v]==1)continue;
dis3[v]=dis3[u]+e[i].w;
dfs3(v,u);
}
return;
}
signed main(){
cin>>n>>m;
int u,v,w;
for(int i=1;i<=m;i++){
u=read(),v=read(),w=read();
add(u,v,w);
add(v,u,w);
}
st=1,pos=1,dis[1]=0;
dfs(st,0);
st=pos,dis[st]=0;
dfs(st,0);
ed=pos;
int ans=dis[ed];
dfs2(st,0);
dfs3(ed,0);
// for(int i=1;i<=n;i++){
// printf("i=%d dis2 %d dis3 %d\n",i,dis2[i],dis3[i]);
// }
int tmp=0;
for(int i=1;i<=n;i++){
int d=min(dis2[i],dis3[i]);
tmp=max(tmp,d);
}
cout<<ans+tmp;
return 0;
}