PPOJ刷题-2

PPOJ刷题-2

1118: 继续畅通工程(kruskal)

题目描述

省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可)。现得到城镇道路统计表,表中列出了任意两城镇间修建道路的费用,以及该道路是否已经修通的状态。现请你编写程序,计算出全省畅通需要的最低成本。

输入

Input

测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( 1< N < 100 );随后的 N(N-1)/2 行对应村庄间道路的成本及修建状态,每行给4个正整数,分别是两个村庄的编号(从1编号到N),此两村庄间道路的成本,以及修建状态:1表示已建,0表示未建。
当N为0时输入结束。

输出

每个测试用例的输出占一行,输出全省畅通需要的最低成本。

样例输入
3
1 2 1 0
1 3 2 0
2 3 4 0
3
1 2 1 0
1 3 2 0
2 3 4 1
3
1 2 1 0
1 3 2 1
2 3 4 1
0
样例输出
3
1
0
#include<bits/stdc++.h>
using namespace std;
const int N=105;

struct Edge{
   int s,e,len;
}edge[N*(N-1)/2];

int n,m,father[N];//分别表示点数,边数,和并查集情况
int findfd(int x)
{
    if(father[x]==x)
        return x;
    return findfd(father[x]);
}

int cmp(Edge a,Edge b)//按照边长进行排序
{
    return a.len<b.len;
}

int Kruskal(int m)
{
    sort(edge+1,edge+m+1,cmp);//对边进行排序
    int cost=0;
    for(int i=1;i<=m;i++){//边数刚好构成最小生成树
        int x=findfd(edge[i].s);
        int y=findfd(edge[i].e);
        if(x!=y){
            father[x]=y;
            cost+=edge[i].len;
        }
    }
    return cost;
}

int main()
{
    while(cin>>n&&n){
        for(int i=1;i<=n;i++)
            father[i]=i;
        m=n*(n-1)/2;
        for(int i=1;i<=m;i++){
            int c,d;
            cin>>edge[i].s>>edge[i].e>>c>>d;
            if(!d) edge[i].len=c;
            else edge[i].len=0;
        }
        printf("%d\n",Kruskal(m));
    }
    return 0;
}

1138: N皇后问题(DFS)

题目描述

在一个N*N的棋盘上,问你有多少不同的方式摆放N个皇后。
每个皇后所处的行、列、两条对角线上都不能有其他皇后。

输入

无需处理到EOF
一个整数N,3<=N<=13

输出

输出不同的方案数

样例输入
4
样例输出
2
#include<bits/stdc++.h>
using namespace std;

int col[32],r[32],l[32];//分别标记行,主对角线和副对角线
int n,ans=0;

void DFS(int row)//每行遍历
{
    if(row==n+1){
        ans++;
        return;
    }
    for(int i=1;i<=n;i++){
        if(!col[i]&&!r[i-row+n]&&!l[i+row])//+n是防止数组越界
        {
            col[i]=r[i-row+n]=l[i+row]=1;
            DFS(row+1);
            col[i]=r[i-row+n]=l[i+row]=0;
        }
    }
}

int main()
{
    cin>>n;
    DFS(1);
    cout<<ans<<endl;
    return 0;
}

1286: PIPI运货(Floyd)

题目描述

PIPI是一个商人,经常需要将货物从A地运到B地,我们可以把PIPI经常活动的区域抽象成一个n个结点的地图,用一个nxn的矩阵表示。
矩阵第i行第j列的值代表PIPI从 i 地将货物运到 j 地所需要的固定费用,若该值为-1则代表 i 和 j之间没有直接的通路,注意道路是双向的。
除了上述固定费用外,PIPI在经过每一个结点时都需要交一次过路费(起点和终点不需要交过路费)。
作为一个精打细算的商人,你能帮PIPI计算出从A地到B地的最少费用是多少吗?

输入

第一行输入结点数目n (0<n<=100)
接下来n行输入一个nxn的矩阵(矩阵的值不大于1000)。
第n+2行输入n个数,代表每个结点的过路费cost(cost<=1000)。
第n+3行输入一个数q (q<=10000),代表PIPI的询问次数。
接下来q行,每行输入两个数字,询问A到B的最少花费。

输出

输出q个数字,代表q次询问的结果。若询问的两个地点不可达,输出-1.

样例输入
5
0 3 22 -1 4
3 0 5 -1 -1
22 5 0 9 20
-1 -1 9 0 4
4 -1 20 4 0
5 17 8 3 1
3
1 3
3 5
2 4
样例输出
21
16
17
#include<bits/stdc++.h>
using namespace std;
const int INF=1e8;

int R[102][102],C[102];

int main()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            int k;
            cin>>k;
            R[i][j]=(k==-1?INF:k);
        }
    }
    for(int j=1;j<=n;j++)
        cin>>C[j];
    for(int k=1;k<=n;k++){//其中的k表示i->j中所经过的点,如果路径长度小就更新
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                if(R[i][k]+R[k][j]+C[k]<R[i][j])
                    R[i][j]=R[i][k]+R[k][j]+C[k];
            }
        }
    }
    int m;
    cin>>m;
    while(m--){
        int x,y;
        cin>>x>>y;
        cout<<R[x][y]<<endl;
    }
    return 0;
}

1304: 盗窃团伙(Floyd)

题目描述

美丽祥和的CSU校园里有许多门面,每个门面都出租给做生意的商户,商户之间都在做着各自的生意。但是在宁静的校园里也会有邪恶势力存在。CSU存在着一个盗窃团伙麓石开,盗窃团伙为首的是鸡腿xiefang,他们总是想着如何去盗窃所有门面商户的商品,然后疯狂的盗取别人的劳动成果。

现在给定n个门面的路线图,若门面i和门面j有一条直接通路,那么在图里面我们用一条无向边来表示i和j可达,边上的权值是门面i和门面j的道路长度。现在鸡腿和xiefang准备在n个门面中选定一个门面租赁,便于偷窃其他所有门面的商品,所以他们对租赁门面的要求是,距离他们租赁门面最远的门面到该门面的路程最短。试问他们应该租赁哪一个门面。

输入

输入第一行包括两个数字n和m , 分别代表CSU的门面数目和门面之间的路径数目( n<=500 m <=10000)。
接下来m行每行输入三个数字 u v w ,代表门面u和门面v之间的距离是w。(1<=u,v <=n , 1<=w <=1000)

输出

输出他们会租赁的门面和与该门面相距最远门面的距离,若有多个合法门面,则输出编号最小的那一个。若他们无法偷窃所有的门面,输出"What a pity!"

样例输入
3 3
1 2 3
1 3 4
2 3 1
样例输出
2 3
#include<bits/stdc++.h>
using namespace std;
const int INF=1e9;

int mp[505][505],fa[505],n,m;

int find_F(int x){
   if(fa[x]!=x)
    fa[x]=find_F(fa[x]);
   return fa[x];
}

void Floyd(){
   for(int k=1;k<=n;k++){
      for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(mp[i][k]+mp[k][j]<mp[i][j])
                mp[i][j]=mp[i][k]+mp[k][j];
        }
      }
   }
}

void solve()
{
    Floyd();
    int center_ans=1,Ans=INF;
    for(int center=1;center<=n;center++){//查找一点到某一点的最远的最小距离
        int MaxDis=0;
        for(int j=1;j<=n;j++){
            MaxDis=max(MaxDis,mp[center][j]);
        }
        if(Ans>MaxDis){
            Ans=min(Ans,MaxDis);
            center_ans=center;
        }
    }
    printf("%d %d\n",center_ans,Ans);
}

int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        fa[i]=i;
        for(int j=1;j<=n;j++){
            mp[i][j]=(i==j?0:INF);
        }
    }
    for(int i=1;i<=m;i++){
        int x,y,c;
        cin>>x>>y>>c;
        mp[x][y]=mp[y][x]=c;
        if(find_F(x)!=find_F(y))
            fa[x]=fa[y];
    }
    int cnt=0;
    for(int i=1;i<=n;i++)
        if(fa[i]==i) cnt++;
    if(cnt>1)
        printf("What a pity!\n");
    else
        solve();
    return 0;
}

1306: 盗窃团伙II(Kruskal)

题目描述

听说PIPI家又有新产品了,盗窃团伙麓石开鸡腿xiefang开始计划着要去PIPI家偷产品了。要是偷到了,他们就可以把PIPI家的产品理不直气也壮高价售出了!!!
CSU的地下有二战时构建的地下交通网络,交通网络中有n个枢纽,m条隧道,每个隧道都连接了两个交通枢纽。麓石开团伙在 1 号枢纽,而PIPI家的产品中心刚好位于n号枢纽,现在他们准备从地下隧道直通PIPI家的产品中心。但是这些隧道已经年久失修,需要翻新一遍才能够安全通过。现在麓石开想请若干家施工公司将其中的一些隧道翻新,使得他们能够从 1 号枢纽走到 n 号枢纽。这些施工公司能够同时开工翻新隧道,但是每一家公司都只能翻新一条隧道。 (两个枢纽之间可能有多条隧道)
麓石开只想着尽可能早一点的偷到PIPI家的新产品,请问至少需要多少天,他们才能够修通隧道,进入PIPI家的产品中心偷产品??

输入

输入的第一行包含两个整数n, m,用一个空格分隔,分别表示交通枢纽的数量和候选隧道的数量 (n<=1e5 , m<=2e5)。
第2行到第m+1行,每行包含三个整数a, b, c,表示枢纽a和枢纽b之间可以修建一条隧道,需要的时间为c天 (1<=a,b<=n , 0<c<=1e5)。

输出

输出盗窃团伙至少需要多少天才能偷到PIPI家的产品?若PIPI足够幸运,让他们没有办法偷到产品,则输出"How lucky!"

样例输入
6 6
1 2 4
2 3 4
3 6 7
1 4 2
4 5 5
5 6 6
样例输出
6
提示

然鹅PIPI并没有 How lucky 的时候 ,o(╥﹏╥)o

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int fa[N],n,m;
struct edge{
    int s,e,c;
}s[2*N];

int cmp(edge a,edge b)
{
    return a.c<b.c;
}

int find_f(int x)//压缩版并查集
{
    return fa[x]==x?x:fa[x]=find_f(fa[x]);
}

int Kruskal(){
    sort(s,s+m,cmp);
    for(int i=0;i<m;i++){

        if(find_f(s[i].s)!=find_f(s[i].e)){
            fa[find_f(s[i].s)]=find_f(s[i].e);
        }
        if(find_f(1)==find_f(n))//找到最少修建好1到n所需的时间
            return s[i].c;
        //因为是从小到大排序,如果1到n所需时间短就会马上输出
        //如果所需时间长,在构建最小生成树的过程中就会输出
        //不管如何所需最少时间都是此刻所连接了1到n的路径时间
    }
    return -1;
}

int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        fa[i]=i;
    for(int i=0;i<m;i++){
        cin>>s[i].s>>s[i].e>>s[i].c;
    }
    int ans=Kruskal();
    if(ans==-1)
        printf("How lucky!\n");
    else
        printf("%d\n",ans);
    return 0;
}

1337: 汉诺塔问题(递归)

题目描述

假设有三个分别命名为A、B和C的塔座,在塔座X上插有n个直径大小各不相同、依小到大编号为1,2,…,n的圆盘。现要求将A轴上的n个圆盘移至塔座C上并仍按同样顺序叠排,圆盘移动时必须遵循下列规则:

1)每次只能移动一个圆盘;

2)圆盘可以插在A、B和C中的任一塔座上;

3)任何时刻都不能将一个较大的圆盘压在较小的圆盘之上。

输入

输入包含多组测试用例。
每组样例输入一个正整数n (n<=15)

输出

对于每组测试样例,输出每一步如何进行移动。

样例输入
1
2
3
样例输出
Move disk 1 from A to C

Move disk 1 from A to B
Move disk 2 from A to C
Move disk 1 from B to C

Move disk 1 from A to C
Move disk 2 from A to B
Move disk 1 from C to B
Move disk 3 from A to C
Move disk 1 from B to A
Move disk 2 from B to C
Move disk 1 from A to C
#include<bits/stdc++.h>
using namespace std;
int n;

void Move(char x,int n,char y){
   printf("Move disk %d from %c to %c\n",n,x,y);
}

void hanoi(int n,char x,char y, char z)
{
    if(n==1) Move(x,1,z);
    else {
        hanoi(n-1,x,z,y);//先将上面n-1个小盘子从A柱经过C柱放到B柱上
        Move(x,n,z);//将最底层的盘子从A柱放到C柱
        hanoi(n-1,y,x,z);//将剩下的n-1个盘子从B柱经过A柱放到C柱
    }
}

int main()
{
    while(cin>>n){
       hanoi(n,'A','B','C');
       printf("\n");
    }
    return 0;
}

1273: 三个有序数组的交集

题目描述

现在有三个有序数组 A , B ,C ,请你求出他们的交集。

输入

第一行输入三个正整数 n , m , q 表示三个有序数组的大小 (1<=n,m,q<=1e5)。
第二行输入数组A。
第三行输入数组B。
第四行输入数组C。

输出

输出一行,表示他们的交集,元素之间以空格分割。

样例输入
5 5 5
1 2 3 4 5
1 2 5 7 9
1 3 4 5 8
样例输出
1 5
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;

int main()
{
    //i、j、k分别为遍历三个数组的指针,x为指向元素的最小值
    int i,j,k;
    int x,n,m,q;
    int A[N],B[N],C[N];
    cin>>n>>m>>q;
    for(i=0;i<n;i++)
        cin>>A[i];
    for(i=0;i<m;i++)
        cin>>B[i];
    for(i=0;i<q;i++)
        cin>>C[i];
    //三个指针分别从起点开始遍历,f初始化为0,当其中一个指针到达终点时就停止遍历
    for(int f=i=j=k=0;i<n&&j<m&&k<q;){
        //若三个指针指向元素相等,则该元素在交集中,输出即可
        if(A[i]==B[j]&&B[j]==C[k]){
            if(f) printf(" ");
            f=1,printf("%d",A[i]);
            i++,j++,k++;
        }//若有不相等
        else{
            // x为三指针指向元素最小的那个
            x=min(A[i],min(B[j],C[k]));
            if(x==A[i]) i++;
            if(x==B[j]) j++;
            if(x==C[k]) k++;
        }
    }
    printf("\n");
    return 0;
}

1295: 一元多项式乘法

题目描述

使用链表实现两个一元多项式A和B的乘法。

输入

第一行输入一个正整数N(0<N<=500),代表链表A中结点的个数。
第二行输入2N个整数,输入的形式为 coffi expi, 代表每一项的系数和指数,输入保证对于任意 i≠j, coffi≠coffj ( 0<|coffi|<1000 , 0<=expi<1000)。
第三行输入一个正整数M(0<M<=500),代表链表B中结点的个数。
第四行输入2
M个整数,输入的形式为 coffi expi, 代表每一项的系数和指数,输入保证对于任意 i≠j, coffi≠coffj ( 0<|coffi|<1000 , 0<=expi<1000)。

输出

输出包括一行, 即按照指数降序输出AB的结果,系数为零的项不能输出。 若AB的结果为空,输出 “0 0”。

样例输入
3
2 1 2 4 3 2
2
4 3 2 4
样例输出
4 8 8 7 6 6 16 5 8 4
#include<bits/stdc++.h>//有点bug
using namespace std;
//利用二重循环实现乘法,并将指数相同的项进行合并
typedef struct ListNode{
    int val,ex;//分别为系数和指数
    ListNode* next;
    ListNode(int v,int e):val(v),ex(e),next(NULL){}
}ListNode,*Polynomial;

void display(Polynomial h){//多项式h存储的时候是从小到大存储,然后利用递归实现从大到小输出
    if(!h) return;
    display(h->next);
    if(h->ex!=-1) printf("%d %d ",h->val,h->ex);
}

Polynomial CreatePoly()
{
    Polynomial L = new ListNode(-1,-1),r=L;
    int n,v,e;
    cin>>n;
    while(n--){
        cin>>v>>e;
        r->next=new ListNode(v,e);
        r=r->next;
    }
    r->next=NULL;//处理最后一个结点
    return L;
}

Polynomial mutiple(Polynomial h1,Polynomial h2){//多项式相乘,返回结果
    Polynomial h = new ListNode(-1,-1),p=h1->next,q=h2->next,r,s;
    int VAL,EX;
    for(;p;p=p->next){
        for(q=h1->next;q;q=q->next){//从h2的头节点开始
            VAL=p->val*q->val;
            EX=p->ex+q->ex;
            
            r=h;
            while(r->next&&EX>r->next->ex) r=r->next;
            if(!r->next||r->next->ex>EX){//如果到达链表尾部或者链表中没有该指数结点
                s = new ListNode(0,0);
                s->ex=EX;
                s->val=VAL;
                s->next=r->next;//将新创建的结点插入到r后面
                r->next=s;
            }else if((r->next->ex==EX)&&(r->next->val+VAL==0)){//若找到指数一样的结点,且系数相互抵消后,直接删除该节点
                s = r->next;
                r->next=s->next;
                delete s;
            }else if((r->next->ex==EX)&&(r->next->val+VAL!=0)){//若找到指数一样的结点,且系数不抵消
                r->next->val+=VAL;//系数相加
            }
        }
    }
    return h;
}

int main()
{
    Polynomial h1=CreatePoly();
    Polynomial h2=CreatePoly();
    Polynomial h=mutiple(h1,h2);
    if(!h)
        printf("0 0");
    else
        display(h);
    return 0;
}

1010: 好坑的电子地图(迪杰斯特拉)

题目描述

小明是今年参加复试的外校考生,他要去民主楼小礼堂签到。由于对中南大学校本部很不熟悉,小明找到了这边读书的好朋友鲁大师,不巧,鲁大师在忙着自由探索项目的结题工作,不能给他带路,只好给他发了一份半成品的电子地图。地图上只列出了校本部内的N个点,M条路,小明处于S点,民主楼小礼堂是T点。小明感谢鲁大师,当然只是在拿到地图的一瞬间,后面的情况让他知道这半成品到底有多坑。鲁大师制作的电子地图是带有语音提示功能的,但是在编号为奇数的点他要等1分钟才能告诉他具体怎么走,而在编号为偶数的点要等2分钟。现在告诉你地图的具体情况,小明想知道他能不能在A分钟内赶到民主楼小礼堂。

输入

输入数据有多组,每组占M+1行,第一行有5个数字N,M,S,T,A,接下来M行,每行三个数字u,v,t,代表每条路的两个顶点和步行时间。(输入数据保证不含重边0<N<M<1000)

输出

对于每组输入数据,输出一行,小明能在A分钟内赶到民主楼小礼堂输出YES和最少花费的时间,否则输出KENG

样例输入
4 3 1 4 10
1 2 1
3 2 2
3 4 3
5 4 2 4 7
1 2 5
5 4 2
3 5 1
2 3 1
样例输出
YES 10
KENG
#include<bits/stdc++.h>
using namespace std;
//常规的最短路径问题,唯一需要注意的是,在奇数点需要等待1分钟,偶数点等待2分钟
//处理方式就是在奇数点出发的边权全部+1,偶数点全部+2
int n,m,s,t,total;
int mp[1010][1010],dis[1010];
int vis[1010];
const int INF =1e9+7;

void init()
{
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(i==j) mp[i][j]=0;
            else mp[i][j]=INF;
        }
    }
}

void Dijtra()
{
    for(int i=1;i<=n;i++)
        dis[i]=mp[s][i];
    vis[s]=1;
    for(int i=1;i<=n-1;i++){
        int minn=INF,minid;
        for(int j=1;j<=n;j++){//把dis中最小的选出
            if(!vis[j]&&minn>dis[j]){
                minn=dis[j];
                minid=j;
            }
        }
        vis[minid]=1;//选出最小节点标记
        for(int j=1;j<=n;j++){//用选出的节点作为中间节点更新dis
            if(!vis[j]&&dis[j]>dis[minid]+mp[minid][j]){
                dis[j]=dis[minid]+mp[minid][j];
            }
        }
    }
    if(dis[t]<=total)
        printf("YES %d\n",dis[t]);
    else
        printf("KENG\n");
}

int main()
{
    while(cin>>n>>m>>s>>t>>total){
        init();
        for(int i=0;i<m;i++){
            int u,v,c;
            cin>>u>>v>>c;
            if(u%2==1) mp[u][v]=c+1;//奇数点时间+1
            else mp[u][v]=c+2;
            if(v%2==1) mp[v][u]=c+1;
            else mp[v][u]=c+2;
        }
        Dijtra();
    }
    return 0;
}

1393: 国防部长PIPI (Kruskal)

题目描述

PIPI国有n个哨所,每个哨所都配置了一台型号相同的无线电通讯设备。设备有一个通讯半径D,如果两个哨站距离超过D,就无法直接通讯。
无线电通讯设备功率越高,通讯半径就越大,但是造价也就越高。为了省钱,PIPI需要确定一个最小的通讯半径D,所有的哨站使用这一型号设备后,任意两个哨站都能进行通讯(直接或间接)。

输入

多组测试用例
第一行为整数n,表示哨所的数目。2<=n<=100。
接下来n行,每行给出一个坐标(x,y),表示第i个哨所的坐标。-50000<=x,y<=50000.

输出

每组数据输出一个实数,表示D的最小值。保留两位小数。

样例输入
4
0 100
0 300
0 600
150 750
样例输出
300.00
#include<bits/stdc++.h>
using namespace std;

typedef pair<int,int> pr;
const int M=1e4+5;

struct Edge{
   int x,y;
   double d;
}E[M];
pr point[105];
int f[105];

int cmp(Edge a,Edge b)
{
    return a.d<b.d;
}

int find_f(int x)
{
    return f[x]==x?x:f[x]=find_f(f[x]);
}

int main()
{
    int n;
    while(cin>>n){
        int id=0;
        for(int i=1;i<=n;i++)
            cin>>point[i].first>>point[i].second,f[i]=i;
        for(int i=1;i<=n;i++){
            for(int j=i+1;j<=n;j++){
                double r=sqrt((point[i].first-point[j].first)*(point[i].first-point[j].first)+(point[i].second-point[j].second)*(point[i].second-point[j].second));//pow(2,(point[i].first-point[j].first))+pow(2,(point[i].second-point[j].second));
                E[id++]={i,j,r};
                //cout<<r<<endl;
            }
        }
        sort(E,E+id,cmp);
        double ans=0;

        for(int i=0;i<id;i++){//将一条条边加入
            int fa=find_f(E[i].x),fb=find_f(E[i].y);
            //cout<<E[i].d<<endl;
            if(fa!=fb){
                f[fa]=fb;
                ans=E[i].d;
            }
        }
        printf("%.2f\n",ans);
    }
    return 0;
}

1282: 数组中的第K个最大元素(快排思想)

题目描述

在数组中找到从小到大排序后第k大的元素。

输入

第一行输入数组长度n(n<=10000) 和 k.
第二行输入n个数字。

输出

输出数组中第k个最大的元素。

样例输入
6 2
3 2 1 5 6 4
样例输出
5
#include<bits/stdc++.h>
using namespace std;
const int N=1e4+5;

int nums[N];

int Partition(int *nums,int low,int high)
{
    int povit=nums[low];
    while(low<high){
        while(low<high&&povit<=nums[high]) high--;
        nums[low]=nums[high];
        while(low<high&&povit>=nums[low]) low++;
        nums[high]=nums[low];
    }
    nums[low]=povit;
    return low;
}

int findk(int *nums,int low,int high,int k){
    int index=Partition(nums,low,high);
    if(index==k)//如果中枢正好是第k大元素,返回
        return nums[index];
    else if(index<k)//中枢元素小于第k大元素,在中枢右边找
        return findk(nums,index+1,high,k);
    else//中枢元素大于第k大元素,在中枢左边找
        return findk(nums,low,index-1,k);
}

int main()
{
    int n,k;
    cin>>n>>k;
    for(int i=1;i<=n;i++){
        cin>>nums[i];
    }
    printf("%d\n",findk(nums,1,n,n-k+1));//注意这里是第k大,所以要n-k+1
    return 0;
}

1360: 删除最外层括号(栈)

题目描述

有效的括号字符串有 () , (A) , A+B, 其中A,B也为有效的括号字符串。若有效的括号字符串S非空,且不存在将S分解为A+B的方法(A,B皆为有效的括号字符串),那么S为不可分解的。给出字符串S,我们将其分解为 S = S1+S2+…+Sn, 其中每一个Si都是不可分解的。
现在要求你将S拆分为n个不可分解的串,并去除掉每一个不可分解串最外层的括号。

输入

输入包含多组测试样例。
每一组测试样例都是一个合法字符串S (|S|<100)。

输出

对于每组样例,输出分解之后然后去除掉括号的字符串。

样例输入
(()())(())
()(())
样例输出
()()()
()
#include<bits/stdc++.h>
using namespace std;

stack<char> st;
string ans;

void solve(string s)//输入的括号串是合法的
{
    ans="";
    for(int i=0;i<s.size();i++){
        if(s[i]=='('){
            if(!st.empty())//如果为’(’,而且栈里有左括号了,那整个左括号不能分解了
               ans+=s[i];
            st.push(s[i]);
        }else{
            st.pop();
            if(!st.empty())//如果为右括号,而且不是最外层的右括号,加入
                ans+=s[i];
        }
        //cout<<ans<<endl;
    }
}

int main()
{
    string s;
    while(cin>>s){
      solve(s);
      cout<<ans<<endl;
    }
    return 0;
}

1407: 八大排序——基数排序

题目描述

请使用基数排序对题中给出的数据进行排序。

输入

输入的第一行包含1个正整数n,表示共有n个整数需要参与排序。其中n不超过100000。
第二行包含n个用空格隔开的正整数,表示n个需要排序的整数。

输出

只有1行,包含n个整数,表示从小到大排序完毕的所有整数。
请在每个整数后输出一个空格,并请注意行尾输出换行。

样例输入
10
2 8 4 6 1 10 7 3 5 9
样例输出
1 2 3 4 5 6 7 8 9 10
#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
const int N=1e5+5;
int D; //最大位数

//获取整数的第i位数u
int GetDigit(int x,int i){
   while(i>1){
      x/=10;
      i--;
   }
   return x%10;
}

//基数排序
void RadixSort(int *num,int len)
{
    int k,l,digit;
    int allot[10][len];
    int vis[10];
    //初始化为0
    memset(allot,0,sizeof(allot));
    for(int i=1;i<=D;i++){
        memset(vis,0,sizeof(vis));
        //将每个数据的第i位分配到allot数组中
        for(int j=0;j<len;j++){
            //获取当前数据的第 j 位
            digit=GetDigit(num[j],i);
            k=0;
            //查找插入的位置
            /*while(allot[digit][k])
                k++;*/
            //放入allot[digit]末尾
            allot[digit][vis[digit]]=num[j];
            vis[digit]++;
        }
        //将分配数组的数据放到原数组中
        l=0;
        for(int j=0;j<10;j++){
            k=0;
            while(allot[j][k])
                num[l++]=allot[j][k++];
        }
        memset(allot,0,sizeof(allot));
    }
}

int main()
{
    int n;
    cin>>n;
    int num[N];
    int M=-INF;
    for(int i=0;i<n;i++){
        scanf("%d",&num[i]);
        M=max(M,num[i]);
    }
    D=0;
    while(M){
        D++;
        M/=10;
    }
    RadixSort(num,n);
    for(int i=0;i<n;i++)
        printf("%d ",num[i]);
    printf("\n");
    return 0;
}

1292: 中缀表达式转后缀表达式II

PIPI现在有若干个包含小写英文字母作为操作数 以及 ‘+’, ‘-’, ‘*’, ‘/’, ‘^’ ,‘(’,')‘七种操作符的合法中缀表达式。请你将其转为后缀表达式(逆波兰式)。
PS:’'代表幂运算,23=8

输入

输入一个字符串s,表示中缀表达式。

输出

输出一个字符串表示对应的后缀表达式。

样例输入
a+b*c+(d*e+f)*g
样例输出
abc*+de*f+g*+
#include<bits/stdc++.h>
using namespace std;

int main()
{
    int v[300];//定义操作符的优先级
    v['(']=0,v['+']=v['-']=1,v['*']=v['/']=2,v['^']=3;
    string s;
    cin>>s;
    stack<char> st;
    for(int i=0;i<s.size();i++){
        if(s[i]>='a'&&s[i]<='z')
            cout<<s[i];
        else if(s[i]=='(')//若是左括号直接入栈
            st.push(s[i]);
        else if(s[i]==')')//若是右括号直接输出栈内元素,直到出栈到左括号
        {
            while(st.top()!='('){
                cout<<st.top();
                st.pop();
            }
            st.pop();//把左括号出栈
        }
        else{
            //若是操作符且该操作符优先级小于等于栈顶操作符优先级
            //输出栈顶元素,直到栈为空或者该操作符优先级比栈顶操作优先级高
            while(!st.empty()&&v[s[i]]<=v[st.top()]){
                cout<<st.top();
                st.pop();
            }
            st.push(s[i]);
        }
    }
    while(!st.empty()){//输出栈内剩余元素
        cout<<st.top();
        st.pop();
    }
    cout<<endl;
    return 0;
}

1311: 删除最少无效括号

题目描述

给你一个仅由 ‘(’、‘)’ 组成的字符串 s。
你需要从字符串中删除最少数目的 ‘(’ 或者 ‘)’ (可以删除任意位置的括号),使得剩下的括号字符串合法。

输入

输入包含一个字符串s , 长度不超过 1e5

输出

输出包含最长的合法字符串。

样例输入
(()))(())((()
样例输出
(())(())()
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;

int main()
{
    string s;
    cin>>s;
    stack<int> st;
    int forbid[N];//标记需要删除括号的位置
    memset(forbid,0,sizeof(forbid));
    for(int i=0;i<s.size();i++){
        if(s[i]=='(')
            st.push(i);
        else{
            if(st.empty())//如果为右括号,且栈为空,说明右括号不合法
                forbid[i]=1;
            else
                st.pop();//栈不为空,匹配成功
        }
    }
    while(!st.empty()){
        forbid[st.top()]=1;
        st.pop();
    }
    for(int i=0;i<s.size();i++){
        if(!forbid[i])
            cout<<s[i];
    }
    return 0;
}

1332: 反转括号之间的子串

题目描述

PIPI有一个字符串s , 请你按照从括号内到外的顺序,逐层反转每对匹配括号中的字符串。(PS: 串中每个左括号都有相应的右括号进行配对)

输入

输入包含多组测试用例。
第一行输入字符串 s ,s的长度不会超过100。

输出

对于每组测试用例,输出反转后的字符串(字符串中不包含任何括号)。

样例输入
(((jo))ipip)
(((jo))(pi)ip)
样例输出
pipioj
pipioj
#include<bits/stdc++.h>
using namespace std;
//遇到左括号,则将做左括号对应的下标压入栈
//遇到右括号,将栈中对应左括号的下标出栈,然后翻转这一段字符串

int main()
{
    string s;
    while(cin>>s){
        stack<int> st;
        for(int i=0;i<s.size();i++){
            if(s[i]=='(')
                st.push(i);
            else if(s[i]==')'){
                int l=st.top();st.pop();
                int r=i;
                reverse(s.begin()+l,s.begin()+r+1);
            }
        }
        string ans;
        for(int i=0;i<s.size();i++){
            if(s[i]!='('&&s[i]!=')')
                ans+=s[i];
        }
        cout<<ans<<endl;
    }
    return 0;
}

1368: 简单模式匹配算法

题目描述

给你两个字符串A与B,请问B是否作为子串在A中出现过?
字符串所有字符均由小写字母组成。

输入

第一行输出字符串A,|A|<=1000。
第二行输入字符串B,|B|<=1000。

输出

若B作为子串在A中出现过,输出YES,否则输出NO。

样例输入
abc
bc
样例输出
YES
#include<bits/stdc++.h>
using namespace std;

int main()
{
    string s1,s2;
    cin>>s1>>s2;
    int flag=0;
    for(int i=0;i+s2.size()<=s1.size();i++){
        for(int j=0,k=i;j<s2.size();j++,k++){
            if(s1[k]!=s2[j])
                break;
            if(j==s2.size()-1)
                flag=1;
        }
        if(flag==1) break;
    }
    if(flag)
        printf("YES\n");
    else
        printf("NO\n");
    return 0;
}

1269: 还原二叉树II(中序+后序->先序)

题目描述

PIPI现在有两个序列,分别为二叉树的中序序列和二叉树的后序序列,他想由这两个序列还原二叉树,你能帮PIPI还原吗?

输入

第一行输入序列的长度n (0<n<100).
第二行输入二叉树的中序序列。
第三行输入二叉树的后序序列。

输出

输出二叉树的先序遍历序列。

样例输入
3
2 1 3
2 3 1
样例输出
1 2 3
#include<bits/stdc++.h>
using namespace std;
const int MaxSize=100;
struct TreeNode {
   int val;
   TreeNode *left;
   TreeNode *right;
};

int inorder[MaxSize],postorder[MaxSize];

TreeNode* build(int inorder[],int postorder[],int l1,int h1,int l2,int h2)
{
    if(l1>h1) return NULL;
    int llen,rlen,i;
    TreeNode * root = new TreeNode;//后序遍历最后一个是根节点
    root->val=postorder[h2];
    for(i=l1;inorder[i]!=root->val;i++);
    llen=i-l1;//左子树长度
    rlen=h1-i;//右子树长度
    root->left=build(inorder,postorder,l1,l1+llen-1,l2,l2+llen-1);//递归找左子树
    root->right=build(inorder,postorder,h1-rlen+1,h1,h2-rlen,h2-1);//递归构造右子树
    return root;
}

void Print(TreeNode * T){
    if(T==NULL) return;
    printf("%d ",T->val);
    Print(T->left);
    Print(T->right);
}

int main()
{
    int n;
    cin>>n;
    for(int i=0;i<n;i++)
        cin>>inorder[i];
    for(int i=0;i<n;i++)
        cin>>postorder[i];
    TreeNode * T=build(inorder,postorder,0,n-1,0,n-1);
    Print(T);
    return 0;
}

1270: 还原二叉树III(二叉查找树+先序)

题目描述

PIPI现在知道了一棵二叉搜索树的先序序列,你能帮PIPI还原这棵二叉树吗?

输入

第一行输入序列的长度n (0<n<100).
第二行输入二叉树的先序序列。

输出

输出二叉树的后序遍历序列。

样例输入
6
8 5 1 7 10 12
样例输出
1 7 5 12 10 8
#include<bits/stdc++.h>
using namespace std;
const int MaxSize=100;
struct TreeNode {
   int val;
   TreeNode *left;
   TreeNode *right;
};
//因为是二分查找树,所以中序遍历就是升序数组
int inorder[MaxSize],preorder[MaxSize];

TreeNode* build(int inorder[],int preorder[],int l1,int h1,int l2,int h2)
{
    if(l1>h1) return NULL;
    int llen,rlen,i;
    TreeNode * root = new TreeNode;//后序遍历最后一个是根节点
    root->val=preorder[l1];
    for(i=l2;inorder[i]!=root->val;i++);
    llen=i-l2;//左子树长度
    rlen=h2-i;//右子树长度
    root->left=build(inorder,preorder,l1+1,l1+llen,l2,l2+llen-1);//递归找左子树
    root->right=build(inorder,preorder,h1-rlen+1,h1,h2-rlen+1,h2);//递归构造右子树
    return root;
}

void Print(TreeNode * T){
    if(T==NULL) return;
    Print(T->left);
    Print(T->right);
    printf("%d ",T->val);
}

int main()
{
    int n;
    cin>>n;
    for(int i=0;i<n;i++)
        cin>>preorder[i],inorder[i]=preorder[i];
    sort(inorder,inorder+n);
    TreeNode * T=build(inorder,preorder,0,n-1,0,n-1);
    Print(T);
    return 0;
}

1263: 节点与其祖先之间的最大差值

题目描述

给定二叉树的根节点 root,找出存在于不同节点 A和 B 之间的最大值V,其中 V = |A.val - B.val|,且 A 是 B 的祖先。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A72J7Fbo-1664854545110)(ipic/20190929211205_54979.jpg)]

输入

输入一行,按照先序输入一棵二叉树,其中空节点用 -1 表示。

输出

输出一行代表最大差值V。

样例输入
8 3 1 -1 -1 6 4 -1 -1 7 -1 -1 10 -1 14 13 -1 -1 -1
样例输出
7
提示

样例输入即为题面的二叉树,最优选择是 |8-1| = 7

#include<bits/stdc++.h>
using namespace std;
const int INF=0x3f3f3f3f;
int ans;//结点差

typedef struct node{
   int w;
   node *left,*right;
}node;

node *build(){//由先序遍历创建二叉树
   int x;
   cin>>x;
   if(x==-1){
      return NULL;
   }
   else{
      node *root= new node;
      root->w=x;
      root->left=build();
      root->right=build();
      return root;
   }
}

void find_ans(node *root,int Max,int Min)
{
    if(root==NULL) return;
    if(root->w>Max) Max=root->w;
    if(root->w<Min) Min=root->w;
    if(ans<Max-Min) ans=Max-Min;
    find_ans(root->left,Max,Min);
    find_ans(root->right,Max,Min);
}

int main()
{
    node *root=build();
    ans=0;
    find_ans(root,-INF,INF);
    cout<<ans<<endl;
    return 0;
}

1264: 更大和树

题目描述

给出二叉搜索树的根节点,该二叉树的节点值各不相同,修改二叉树,使每个节点node 的新值等于原树中大于或等于 node.val 的值之和。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uOzJfe2H-1664854545114)(ipic/20190930223033_36038.png)]

输入

输入一行,按照先序输入一棵二叉树,其中空节点用 -1 表示。

输出

输出更大和树的先序序列。

样例输入
4 1 0 -1 -1 2 -1 3 -1 -1 6 5 -1 -1 7 -1 8 -1 -1
样例输出
30 36 36 -1 -1 35 -1 33 -1 -1 21 26 -1 -1 15 -1 8 -1 -1
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;

struct TreeNode {
    int val;
    TreeNode * left;
    TreeNode * right;
};
int sum=0;//统计累加值,便于快速更改结点值

void DFS(TreeNode *root)
{
    if(root==NULL) return;
    DFS(root->right);//先遍历右边,因为是线索二叉树,右子树结点值大
    sum+=root->val;
    root->val=sum;
    DFS(root->left);
}

void build(TreeNode * &T)
{
    int x;
    cin>>x;
    if(x==-1){
        T=NULL;
        return;
    }
    else{
        T=new TreeNode;
        T->val=x;
        T->left=T->right=NULL;
        build(T->left);
        build(T->right);
    }
}

void Print(TreeNode * T){//先序遍历
   if(T==NULL){
      printf("-1 ");
      return;
   }
   printf("%d ",T->val);
   Print(T->left);
   Print(T->right);
}
int main()
{
    TreeNode *T=NULL;
    build(T);
    DFS(T);
    Print(T);
    return 0;
}

1310: 同构二叉树

题目描述

如果T1可以通过若干次左右孩子互换变成T2,则我们称两棵树是“同构”的。 例如图1给出的两棵树就是同构的,因为我们把其中一棵树的结点A、B、G的左右孩子互换后,就得到另外一棵树。而图2就不是同构的。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cRhVxyrw-1664854545116)(ipic/20191206192628_49456.png)]
图一
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-joh224GU-1664854545118)(ipic/20191206192728_19233.png)]
图二

输入

第一行按照先序输入T1,其中空节点用 -1 表示。
第二行按照先序输入T2,其中空节点用 -1 表示。

输出

如果两棵树是同构的,也就说明麓石开盗窃了PIPI的资料,输出"YES"。否则输出"NO".

样例输入
1 2 4 -1 -1 5 6 -1 -1 -1 3 7 8 -1 -1 -1 -1
1 3 7 -1 8 -1 -1 -1 2 5 6 -1 -1 -1 4 -1 -1
样例输出
YES
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;

struct TreeNode {
    int val;
    TreeNode * left;
    TreeNode * right;
};

void build(TreeNode * &T)
{
    int x;
    cin>>x;
    if(x==-1){
        T=NULL;
        return;
    }
    else{
        T=new TreeNode;
        T->val=x;
        T->left=T->right=NULL;
        build(T->left);
        build(T->right);
    }
}

bool issimilar(TreeNode *A,TreeNode *B)
{
    if(!A&&!B) return true;//如果都为空,则同构
    if(!A&&B || A&&!B || A->val!=B->val) return false;//如果一空一非空,或者当前结点值不同,则不同构
    //如果左左子树同构,右右子树同构,或者一左一右同构,即同构
    if(issimilar(A->left,B->left)&&issimilar(A->right,B->right)) return true;
    if(issimilar(A->left,B->right)&&issimilar(A->left,B->right)) return true;
    return false;//否则不同构
}

int main()
{
    TreeNode *T=NULL,*T1=NULL;
    build(T);
    build(T1);
    if(issimilar(T,T1))
        printf("YES\n");
    else
        printf("NO\n");
    return 0;
}

1301: 交换二叉树的左右子树

题目描述

给定一棵二叉树,交换二叉树的左右子树。

输入

输入一行,按照先序输入一棵二叉树,其中空节点用 -1 表示。

输出

输出交换后的二叉树的先序序列,空节点无需输出。

样例输入
1 2 -1 -1 3 -1 -1
样例输出
1 3 2
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;

struct TreeNode {
    int val;
    TreeNode * left;
    TreeNode * right;
};

void build(TreeNode * &T)
{
    int x;
    cin>>x;
    if(x==-1){
        T=NULL;
        return;
    }
    else{
        T=new TreeNode;
        T->val=x;
        T->left=T->right=NULL;
        build(T->left);
        build(T->right);
    }
}

void Print(TreeNode * T){//先序遍历
   if(T==NULL) return;
   printf("%d ",T->val);
   Print(T->left);
   Print(T->right);
}

void Exchange(TreeNode * &T){
   if(T==NULL) return;
   Exchange(T->left);
   Exchange(T->right);
   swap(T->left,T->right);//交换左右子树
}

int main()
{
    TreeNode *T=NULL;
    build(T);
    Exchange(T);
    Print(T);
    return 0;
}

1293: 手性二叉树

题目描述
    1
   / \
  2   2
 / \ / \
3  4 4  3
    1
   / \
  2   2
 / \ / \
4  3 4  3
输入

输入一行,按照先序输入一棵二叉树,其中空节点用 -1 表示。

输出

若该二叉树是手性二叉树,输出 “yes”, 否则输出"no"。

样例输入
1 2 3 -1 -1 4 -1 -1 2 4 -1 -1 3 -1 -1
样例输出
yes
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;

struct TreeNode {
    int val;
    TreeNode * left;
    TreeNode * right;
};

void build(TreeNode * &T)
{
    int x;
    cin>>x;
    if(x==-1){
        T=NULL;
        return;
    }
    else{
        T=new TreeNode;
        T->val=x;
        T->left=T->right=NULL;
        build(T->left);
        build(T->right);
    }
}

void Print(TreeNode * T){//先序遍历
   if(T==NULL) return;
   printf("%d ",T->val);
   Print(T->left);
   Print(T->right);
}

bool symmetry(TreeNode *T1,TreeNode *T2)
{
    if(!T1&&!T2) return true;//全部为空,则为对称
    if(!T1 || !T2) return false;//一颗为空,一颗不为空
    if(T1->val!=T2->val) return false;
    //T1的左子树和T2的右子树相等,T1的右子树和T2的左子树相等
    return symmetry(T1->left,T2->right)&&symmetry(T1->right,T2->left);
}

int main()
{
    TreeNode *T=NULL;
    build(T);
    if(symmetry(T,T))
        printf("yes\n");
    else
        printf("no\n");
    return 0;
}

1297: 树中节点的祖先

题目描述

PIPI有一棵结点值均不相同的二叉树,现在他想知道某结点的祖先结点有哪些,你能帮PIPI解决这个问题吗?
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lezGXUuU-1664854545120)(ipic/20191114105918_42188.jpg)]
比如说值为13的结点的祖先为 8 10 14

输入

第一行按照先序输入一棵二叉树,其中空节点用 -1 表示。
第二行输入待查询结点的值。

输出

输出一行,代表该结点的祖先节点,从根节点开始输出。若树中无该结点,输出"No Node!"。若树中某结点无祖先,输出 “No Ancestor!”

样例输入
8 3 1 -1 -1 6 4 -1 -1 7 -1 -1 10 -1 14 13 -1 -1 -1
13
样例输出
8 10 14
法一:非递归方法
#include<bits/stdc++.h>
using namespace std;
const int N=100;
//利用栈去存储后序遍历过程中的结点,然后进行打印输出
struct TreeNode {
   int val;
   TreeNode *left,*right;
};

typedef struct {
   TreeNode *t;
   int tag;// tag为 0 代表左子树被访问,为 1 代表右子树别访问
}Stack;
Stack s[N];

void PostOrder(TreeNode *T,int x){
   TreeNode *p=T;
   int top=0;
   while(p||top>0){
      while(p&&p->val!=x){//一直沿左分支向下
         top++;
         s[top].t=p;
         s[top].tag=0;
         p=p->left;
      }
      if(p&&p->val==x){ //如果找到结点x,打印所有祖先结点
         for(int i=1;i<=top;i++)
            printf("%d ",s[i].t->val);
         if(top<1)// 结点x就是根结点
            printf("No Ancestor!\n");
         return;
      }
      while(top>0 && s[top].tag==1)// 该节点的左右子树都已访问,访问根结点
         top--;
      //这两者顺序不可调换,否则会漏掉祖先结点
      if(top>0){// 在该结点的左子树未找到x,访问该节点的右子树
         s[top].tag=1;
         p=s[top].t->right;
      }
   }
   printf("No Node!\n");
}

void build(TreeNode * &T)
{
    int x;
    cin>>x;
    if(x==-1){
        T==NULL;
        return ;
    }
    T=new TreeNode;
    T->val=x;
    T->left=T->right=NULL;
    build(T->left);
    build(T->right);
}

int main()
{
    TreeNode * T=NULL;
    build(T);
    int x;
    cin>>x;
    PostOrder(T,x);
    return 0;
}
法二:递归方法
#include<bits/stdc++.h>
using namespace std;
const int N=100;
//利用栈去存储后序遍历过程中的结点,然后进行打印输出
struct TreeNode {
   int val;
   TreeNode *left,*right;
};

int flag=0;//标记是否找到结点x
int s[200],x;

void Find_x(TreeNode * T,int n)//n表示T结点前面已经有n个祖先了
{
    //如果该节点为空,或者已经找到了x结点,停止遍历
    if(flag||!T) return ;
    //如果为x结点
    if(T->val==x){
        flag=1;
        //如果S中没有元素,表示该结点没有祖先
        if(!n)
            printf("No Ancestor!");
        //否则输出其祖先结点
        else{
            for(int i=0;i<n;i++)
                printf("%d ",s[i]);
        }
        return;
    }
    else//若该节点不是x结点,将其存在s中
        s[n]=T->val;
    Find_x(T->left,n+1);
    Find_x(T->right,n+1);
}

void build(TreeNode * &T)
{
    int x;
    cin>>x;
    if(x==-1){
        T==NULL;
        return ;
    }
    T=new TreeNode;
    T->val=x;
    T->left=T->right=NULL;
    build(T->left);
    build(T->right);
}

int main()
{
    TreeNode * T=NULL;
    build(T);
    cin>>x;
    Find_x(T,0);
    if(!flag)
        printf("No Node!");
    return 0;
}

1302: PIPI的族谱(判断两个结点是否是兄弟还是堂兄弟)

题目描述

PIPI最近在看家里的族谱,发现族谱刚好组成了一棵二叉树,现在PIPI想询问族谱中的两个结点是否为兄弟或者堂兄弟。
兄弟: 深度相同, 双亲节点相同(同一个结点不能是兄弟)。
堂兄弟: 深度相同,双亲节点不同。

输入

第一行按照先序输入族谱代表的二叉树,其中空节点用 -1 表示。
第二行输入两个数字 x y,代表询问的两个结点的值。

输出

若询问的两个结点是兄弟,输出"brother" , 若询问的两个结点是堂兄弟,输出"cousin" ,否则输出"other relathionship"
(relationship写错了 , 请同学们直接复制"other relathionship")

样例输入
1 2 -1 4 -1 -1 3 -1 5 -1 -1
4 5
样例输出
cousin
#include<bits/stdc++.h>
using namespace std;
const int N=100;
//利用栈去存储后序遍历过程中的结点,然后进行打印输出
struct TreeNode {
   int val;
   TreeNode *left,*right;
};

int flag=0;//标记是否a,b为兄弟结点

void build(TreeNode * &T)
{
    int x;
    cin>>x;
    if(x==-1){
        T==NULL;
        return ;
    }
    T=new TreeNode;
    T->val=x;
    T->left=T->right=NULL;
    build(T->left);
    build(T->right);
}

int depth(TreeNode *T,int h,int x)
{
    int l,r;//分别是x在左子树的深度和右子树的深度
    if(!T) return 0;//在这边子树上没找到结点x
    //找到返回深度
    if(T->val==x) return h;
    l=depth(T->left,h+1,x);
    r=depth(T->right,h+1,x);
    //左右子树肯定只有一边有结点x,另一边是返回0
    return l?l:r;
}

void judge(TreeNode *T,int a,int b){
   //若标志flag已经为1,或者该节点为空,停止遍历
   if(flag||!T) return;
   //若该节点的左右孩子正好是a,b结点,将flag置1
   if(T->left&&T->right&&((T->left->val==a&&T->right->val==b)||(T->left->val==b&&T->right->val==a))){
      flag=1;
      return;
   }
   judge(T->left,a,b);
   judge(T->right,a,b);
}

int main()
{
    TreeNode * T=NULL;
    build(T);
    int a,b;
    cin>>a>>b;
    int da=depth(T,1,a);
    int db=depth(T,1,b);
    judge(T,a,b);//判断是否为兄弟
    if(da==db){
        if(flag)
            printf("brother\n");
        else
            printf("cousin\n");
    }
    else
        printf("other relathionship\n");
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值