PPOJ刷题-1

PPOJ刷题-1

1213:顺序表的删除

题目描述

从顺序表L中删除具有最小值的元素(假设唯一)并友函数返回被删元素的值。空出的元素由最后一个元素填补。

输入

输入包含一个整数n代表顺序表L长度。
接下来包含n个整数,代表顺序表L中的元素。

输出

若顺序表为空,输出 “error”.
若不为空,输出最小元素的值并输出删除最小值之后的顺序表。

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

bool Del_Min(int *L,int n,int& x){
    if(n==0)
        return false;
    int pos=0;
    x=L[0];
    for(int i=1;i<n;i++){
        if(L[i]<x){
            pos=i;
            x=L[i];
        }
    }
    L[pos]=L[n-1];
    return true;
}

int main()
{
    int n;
    cin>>n;
    int L[100];
    for(int i=0;i<n;i++){
        cin>>L[i];
    }
    int Min;
    if(Del_Min(L,n,Min)){
        cout<<Min<<endl;
        for(int i=0;i<n-1;i++)//链表中个数减一
            printf("%d ",L[i]);
        printf("\n");
    }else{
        cout<<"error"<<endl;
    }
    return 0;
}

1228: 顺序表的删除I

题目描述

长度为n的顺序表L,编写一个时间复杂度为O(n),空间复杂度为O(1)的算法,删除线性表中所有值为x的数据元素。

输入

输入包含一个整数n代表顺序表L长度,一个x代表要删除的元素。
接下来包含n个整数,代表顺序表L中的元素。

输出

输出删除元素x后的顺序表。

样例输入
5 2
1 3 2 5 2
样例输出
1 3 5
#include<bits/stdc++.h>
using namespace std;
const int MaxSize=500;
typedef int ElemType;
struct Sqlist{
   ElemType data[MaxSize];
   int length;
};

void Del(Sqlist &L,ElemType x)
{
    int k=0;
    for(int i=0;i<L.length;i++){
        if(L.data[i]==x){
            k++;
        }else{
            L.data[i-k]=L.data[i];//将值不等于x的数往前移
        }
    }
    L.length-=k;
}

void Print(Sqlist &L)
{
    for(int i=0;i<L.length;i++){
        printf("%d ",L.data[i]);
    }
    printf("\n");
}

int main()
{
    Sqlist L;
    int n,x;
    cin>>n>>x;
    for(int i=0;i<n;i++){
        cin>>L.data[i];
    }
    L.length=n;
    Del(L,x);
    Print(L);
    return 0;
}

1214: 逆置顺序表

题目描述

PIPI现在由一个顺序表L,他想把顺序表所有元素逆置,要求除了存储L的空间外,辅助的空间复杂度为O(1).

输入

输入包含一个整数n代表顺序表L长度。
接下来包含n个整数,代表顺序表L中的元素。

输出

输出逆置后的顺序表

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

void Print(int *L,int n)
{
    for(int i=0;i<n;i++){
        printf("%d ",L[i]);
    }
    printf("\n");
}

void Reverse(int *L,int n)
{
    for(int i=0;i<n/2;i++){
        swap(L[i],L[n-i-1]);
    }
    Print(L,n);
}

int main()
{
    int n;
    cin>>n;
    int L[100];
    for(int i=0;i<n;i++){
        cin>>L[i];
    }
    Reverse(L,n);
    return 0;
}

1544: 删除链表绝对值相同的元素

题目描述

给定一个单链表,请你删除其中绝对值相同的结点,只保留出现第一次的结点。
链表中的元素的绝对值小于10000。

输入

输入一行数据,以EOF结束,代表一个单链表。

输出

输出删除多余的绝对值相同的元素后的链表

样例输入
2 4 -2 3 1 -3
样例输出
2 4 3 1
提示

此题是为了锻炼大家对链表算法的熟悉程度,请大家用链表来完成

#include<bits/stdc++.h>
using namespace std;

typedef struct node
{
    int val;
    node *next;
}*List;

bool vis[10010];//标记数组

void DelSame(List &L)//
{
    List p = L->next,q = L;
    L->next = NULL;
    while(p){
        List r = p->next;
        if(!vis[abs(p->val)]){
            p->next = NULL;//断开P节点
            q->next = p;
            q = p;
            vis[abs(p->val)]=1;
        }
        p = r;
    }
}

int main()
{
    List head = new node(),p = head;//定义链表
    int x;
    while(cin>>x){
        List s = new node();
        s->val = x;
        s->next = NULL;
        p->next = s;
        p = s;//尾插法
    }
    DelSame(head);
    p = head->next;
    while(p){
        printf("%d ",p->val);
        p = p->next;
    }
    printf("\n");
    return 0;
}

1267: 删除单链表的倒数第K个节点

题目描述

给定一个长度为n的单链表,删除倒数第K的节点,然后从头到尾输出每个节点的值。

输入

第一行包含两个整数N,k,k<=N.
第二行包含N个整数,代表从表头到表尾每个节点的值。
你需要建立单链表把这N个数串起来~

输出

按顺序输出删除了倒数第K个节点后每个节点的值。

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

typedef struct node{
   node *next;
   int val;
   node(){next=NULL;}
};

int main()
{
    int n,k,v;
    cin>>n>>k;
    node *head=new node(),*p=head;
    for(int i=1;i<=n;i++){
        cin>>v;
        p->val=v;
        if(i!=n){
            p->next=new node;
            p=p->next;
        }
    }
    p=head;
    k=n-k+1;
    if(k==1){//如果是第一个节点
        node *q=head;
        head=head->next;
        delete q;//删除第一个节点
    }
    p=head;
    int cnt=1;
    while(p){
        printf("%d ",p->val);
        if(cnt==k-1){
            node *q=p->next;
            p->next=q->next;
            delete q;
        }
        p=p->next;
        cnt++;
    }
    delete head;//释放节点,节省空间
    return 0;
}

1271: 反转链表

题目描述

反转长度为N的单链表从位置 LR 的子段。请在常数空间复杂度下使用一趟扫描完成反转。

输入

第一行三个整数N,L,R,1<=L<=R<=N
接下来N个数表示N个节点的值

输出

输出反转后的单链表节点值

样例输入
5 2 4
1 2 3 4 5
样例输出
1 4 3 2 5
#include<bits/stdc++.h>
using namespace std;
typedef struct node{
    node *next;
    int val;
    node(){}
    node(int x) :val(x),next(NULL) {}
};

node* reverseBetween(node *head,int m,int n)
{
    node *preL=NULL,*L=NULL,*sufR=NULL,*H=new node,*q;
    //preL指向第m个节点前一个节点,L指向第m个节点,sufR指向第n个节点的后一个节点
    int c=1,flag=0;
    if(m==1)
        flag=1;
    for(node *p=head;p;c++){
        if(c==m-1) preL=p;
        else if(c==m){
            L=p;
            flag=1;
        }
        else if(c==n+1){
            sufR=p;
            flag=0;
        }
        if(flag){//使用头插法 放到H为头指针的链表上
            q=p->next;
            p->next=H->next;
            H->next=p;
            p=q;
        }else p=p->next;
    }
    L->next=sufR;
    if(preL){
        preL->next=H->next;
        return head;
    }else{
        return H->next;
    }
}

void print(node *x){
    printf("%d ",x->val);
    if(x->next) print(x->next);
}

int main()
{
    int n,L,R,v;
    cin>>n>>L>>R;
    node *head=new node,*p=head;
    for(int i=1;i<=n;i++){
        cin>>v;
        p->next=new node(v);
        p=p->next;
    }
    print(reverseBetween(head->next,L,R));
    return 0;
}

1275: 约瑟夫环

解析:

使用循环双向链表来模拟这一过程,设置p指针一开始这项编号为1的节点,每一动m-1次,输出该节点的编号病删去,知道全部节点都删去。

题目描述

N个人坐成一个圆环(编号为1 - N),从第1个人开始报数,数到K的人出列,后面的人重新从1开始报数。问最后剩下的人的编号。
例如:N = 3,K = 2。2号先出列,然后是1号,最后剩下的是3号。

输入
2个数N和K,表示N个人,数到K出列。(2 <= N <= 100, 2 <= K <= 100)
输出
最后剩下的人的编号
样例输入
3 2
样例输出
3
#include<bits/stdc++.h>
using namespace std;
typedef struct node{
    node *pre,*next;//前驱,后继
    int id;//编号
    node(int id):id(id){}
};
int main()
{
    int n,m;
    cin>>n>>m;
    node *head=new node(1),*last=head,*now;//不带头结点
    for(int i=2;i<=n;i++){
        now=new node(i);//now指向创建的新节点
        now->pre=last;
        last->next=now;
        last=now;
    }
    head->pre=last;//将最后一个节点与第一个节点相联系起来
    last->next=head;
    node *p=head;//通过p节点来移动输出和删除节点
    while(p->next!=p){
        for(int i=0;i<m-1;i++){
            p=p->next;
        }
        now=p->next;
        p->pre->next=now;//删除p的过程
        p->next->pre=p->pre;
        p=now;//将p赋值成now
    }
    printf("%d\n",now->id);//输出最后
    return 0;
}

1294: 多项式加法

解析:

输入时,按照指针大小顺序升序排成一个单链表,然后利用归并排序的思想将两个单链表相加。

题目描述

PIPI有两个多项式PA和PB,现在告诉你两个多项式的项数、每项的系数以及指数,现在它想知道两个多项式相加的结果,请你帮帮它!

输入

单组输入。
第一行两个整数n,m,分别表示PA、PB的项数。0<=n,m<=1000.
接下来n行,描述PA的各项,每行两个整数a,b,a为该项的指数,b为系数,即bxa
接下来m行,描述PB的各项,每行两个整数a,b,a为该项的指数,b为系数,即bxa
其中0<=a,b<=100000.
注意给出的每项指数可能相等。

输出

按指数从小到大输出PA+PB中系数不为0的每项。每行两个整数a,b,a为指数,b为系数。

样例输入
3 2
0 3
1 4
2 5
0 7
3 6
样例输出
0 10
1 4
2 5
3 6
#include<bits/stdc++.h>
using namespace std;
typedef struct node{
    int b,a;
    node *next;
}LNode,*poly;

void init(poly &La,poly &Lb)
{
    La=new LNode;
    Lb=new LNode;
    La->next=NULL;
    Lb->next=NULL;
    int m,n,a,b;
    cin>>m>>n;
    for(int i=0;i<m;i++){
        cin>>a>>b;
        poly p=new LNode;
        p->next=NULL;
        p->a=a;
        p->b=b;
        poly L=La;//L指向头结点
        while(L->next!=NULL && p->a > L->next->a){
            L=L->next;
        }
        if(L->next!=NULL && p->a==L->next->a){//指数相同,系数相加
            L->next->b+=p->b;
        }
        else{//否则将p插入最后一个小于该指数节点的后面
            p->next=L->next;
            L->next=p;
        }
    }
    for(int i=0;i<n;i++){
        cin>>a>>b;
        poly p=new LNode;
        p->next=NULL;
        p->a=a;
        p->b=b;
        poly L=Lb;
        while(L->next!=NULL && p->a > L->next->a){
            L=L->next;
        }
        if(L->next!=NULL && p->a==L->next->a){
            L->next->b+=p->b;
        }
        else{
            p->next=L->next;
            L->next=p;
        }
    }
}

void polyAdd(poly La,poly Lb)
{
    //带有头结点
    poly pa=La->next;
    poly pb=Lb->next;
    while(pa!=NULL && pb!=NULL){
        if(pa->a==pb->a){
            if(pa->b+pb->b!=0)
                printf("%d %d\n",pa->a,pa->b+pb->b);
            pa=pa->next;
            pb=pb->next;
        }
        else if(pa->a < pb->a){
            printf("%d %d\n",pa->a,pa->b);
            pa=pa->next;
        }
        else if(pa->a > pb->a){
            printf("%d %d\n",pb->a,pb->b);
            pb=pb->next;
        }
    }
    while(pa!=NULL){
        printf("%d %d\n",pa->a,pa->b);
        pa=pa->next;
    }
    while(pb!=NULL){
        printf("%d %d\n",pb->a,pb->b);
        pb=pb->next;
    }
}

int main()
{
    poly La,Lb;
    init(La,Lb);
    polyAdd(La,Lb);
    return 0;
}

1229: 括号匹配

题目描述

假设一个算术表达式中包含圆括号,方括号,花括号3种类型的括号,编写算法来判别表达式中括号是否配对。

输入

输入包含多组测试用例。
对于每组测试样例,包括一个仅由 ‘(’,‘)’,‘[’,‘]’,‘{’,'}'组成的字符串s。

输出

若s是合法的括号串,输出"yes",否则,输出"no"。

样例输入
[]((()))
{()}(]
样例输出
yes
no
#include<bits/stdc++.h>
using namespace std;

bool check(string s)
{
    stack<char> k;
    while(!k.empty()) k.pop();
    for(int i=0;i<s.size();i++){
        if(s[i]=='('||s[i]=='['||s[i]=='{')
            k.push(s[i]);
        else if(!k.empty()&&(s[i]==')'&&k.top()=='('||s[i]==']'&&k.top()=='['||s[i]=='}'&&k.top()=='{'))
            k.pop();
        else
            return false;
    }
    return k.empty();
}

int main()
{
    string s;
    while(cin>>s){
        if(check(s))
            printf("yes\n");
        else
            printf("no\n");
    }
    return 0;
}

1036: 括号匹配

题目描述

PIPI给你一个合法的括号序列,希望跟你按左括号下标递增顺序给出每对括号在序列中的下标。(下标从1开始)

输入

多组数据,请处理到EOF。
对于每组数据,第一行包括一个只包含’(‘,’)'的字符串,保证输入的括号匹配序列合法,长度不超过100000

输出

按左括号下标递增顺序给出每对括号在序列中的下标。

样例输入
(())()()
样例输出
1 4  
2 3  
5 6  
7 8
#include<bits/stdc++.h>
using namespace std;

string s;
int a[100010];

int main()
{
    while(cin>>s){
        stack<int> st;
        int cnt=0;
        for(int i=0;i<s.size();i++){
            cnt++;
            if(s[i]=='('){
                st.push(cnt);
            }
            else{
                a[st.top()]=cnt;
                st.pop();
            }
        }
        for(int i=1;i<cnt;i++){
            if(a[i]!=0){
                printf("%d %d\n",i,a[i]);
                a[i]=0;
            }
        }
    }
    return 0;
}

1366: KMP字符串模式匹配算法

题目描述

KMP算法是字符串模式匹配算法中较为高效的算法之一,其在某次子串匹配母串失败时并未回溯母串的指针而是将子串的指针移动到相应的位置。严蔚敏老师的书中详细描述了KMP算法,同时前面的例子中也描述了子串移动位置的数组实现的算法。前面你已经实现了子串移动的数组,现在就来利用该数组来实现KMP模式匹配。

输入

3组字符串,每组字符串占一行。每行包含由空格分隔的两个字符串,字符串仅由英文小写字母组成且长度不大于100。

输出

每组数据输出两行,
第一行输出模式串的next数组
第二行输出模式串在母串中的位置,如果不匹配,则输出0。

样例输入
string str
thisisalongstring isa
nosubstring subt
样例输出
0 1 1
1
0 1 1
5
0 1 1 1
0
#include<bits/stdc++.h>
using namespace std;

string S,T;
int Next[110];

void get_next(string s)
{
    Next[0]=-1;
    int i=0,j=-1;
    while(i<s.size()-1){
        if(j==-1||s[j]==s[i]){
            j++;
            i++;
            Next[i]=j;
        }
        else
            j=Next[j];
    }
    for(int i=0;i<s.size();i++){
        printf("%d ",Next[i]+1);
    }
    printf("\n");
    return;
}

int Index_KMP(string s,string t)
{
    int i=0,j=0;
    while(i<s.size()&&j<t.size()){
        if(s[i]==t[j]){
            i++;
            j++;
        }
        else
            j=Next[j];
        if(j==-1){
            i++;
            j++;
        }
    }
    if(j>=t.size())
        return i-t.size()+1;
    else
        return 0;
}

int main()
{
    int n=3;
    while(n--){
        cin>>S>>T;
        get_next(T);
        printf("%d\n",Index_KMP(S,T));
        memset(Next,0,sizeof(Next));
    }
    return 0;
}

1362: 计算表达式

题目描述

对于一个不存在括号的表达式进行计算(包含加减乘除四种运算符,除法为向下取整)。

输入

多组数据,每组数据占据一行。

输出

输出计算结果。

样例输入
6/2+3+3*4
734/2-56*2-7*8
样例输出
18
199
#include<bits/stdc++.h>
using namespace std;

char str[1010];
int c;
int a[1010];

int GetNum(){
    int num=0;
    while(str[c]!='\0'&&isdigit(str[c])){
        num=num*10+str[c]-'0';
        c++;
    }
    return num;
}

int main()
{
    while(scanf("%s",str)!=EOF){
        int sign=1,id=0;
        c=0;
        if(str[c]=='-') c++,sign=-1;
        while(str[c]!='\0'){
            int num1=GetNum();
            if(str[c]!='\0'&&(str[c]=='*'||str[c]=='/')){
                char op = str[c];
                c++;
                int num2=GetNum();
                if(op=='*') num1=num1*num2;
                else num1=num1/num2;
            }
            a[id++]=sign*num1;
            if(str[c]=='-') sign=-1;
            else if(str[c]=='+') sign=1;
            else break;
            c++;
        }
        int sum=0;
        for(int i=0;i<id;i++)
            sum+=a[i];
        printf("%d\n",sum);
    }
    return 0;
}

1291: 中缀表达式转后缀表达式I

题目描述

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

输入

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

输出

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

样例输入
a^b+c*d/e-f
样例输出
ab^cd*e/+f-
#include<bits/stdc++.h>
using namespace std;

int main()
{
    int top=-1,i,V[200];
    char Stack[999],R[999];
    V['+']=V['-']=0,V['*']=V['/']=1,V['^']=2;
    scanf("%s",R);
    for(i=0;R[i]!='\0';i++){
        if(R[i]>='a'&&R[i]<='z')
            printf("%c",R[i]);
        else{
            while(top!=-1&&V[R[i]]<=V[Stack[top]])
                printf("%c",Stack[top--]);
            Stack[++top]=R[i];
        }
    }
    while(top!=-1)
        printf("%c",Stack[top--]);
    return 0;
}

1260: 相邻相同字母删除

题目描述

PIPI现在有一段由小写字母组成的文本s,他每天的工作就是找到文本中两个相邻并且相同的字母,然后删除它们。注意这个过程是递归的,比如:
“abbac”->“aac”->“c”。
返回PIPI删除的文本。

输入

输入一行,代表文本s。(1<=|s|<=1e5).

输出

输出一行,代表PIPI经过上述操作之后得到的文本。

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

stack<char> st;
char S[N];

int main()
{
    scanf("%s",S);
    int len=strlen(S);
    string t="";
    for(int i=0;i<len;i++){
        if(!st.empty()&&st.top()==S[i])
            st.pop();
        else
            st.push(S[i]);
    }
    while(!st.empty()){
        t+=st.top();
        st.pop();
    }
    reverse(t.begin(),t.end());
    cout<<t<<endl;
    return 0;
}

1268: 还原二叉树I

题目描述

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

输入

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

输出

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

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

int preorder[100],inorder[100];

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

TreeNode *build(int preorder[],int inorder[],int l1,int h1,int l2,int h2)
{
    if(l1>h1) return NULL;
    int i,llen,rlen;
    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(preorder,inorder,l1+1,l1+llen,l2,l2+llen-1);//构建左子树
    root->right=build(preorder,inorder,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];
    for(int i=0;i<n;i++)
        cin>>inorder[i];

    TreeNode *T=build(preorder,inorder,0,n-1,0,n-1);
    Print(T);
    return 0;
}

1272: 验证BST

题目描述

给定一个二叉树,判断其是否是一棵二叉搜索树。
二叉搜索树具有如下特征:
1.节点的左子树只包含小于当前节点的数。
2.节点的右子树只包含大于当前节点的数。
3.所有左子树和右子树自身必须也是二叉搜索树。

输入

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

输出

若该二叉树为BST,输出"true" ,否则输出"false"(不带引号).

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

typedef struct TreeNode{
   int val;
   TreeNode *lchild;
   TreeNode *rchild;
};

void BuildTree(TreeNode* &T){//按照先序遍历建树
    int key;
    cin>>key;
    if(key==-1){
        T=NULL;
        return;
    }
    else{
        T = new TreeNode;
        T->val=key;
        T->lchild=NULL;
        T->rchild=NULL;
        BuildTree(T->lchild);
        BuildTree(T->rchild);
    }
}

bool isBST(TreeNode* root){
    //cout<<root->val<<endl;
    if(root==NULL)
        return true;
    else if(root->lchild!=NULL&&root->val<=root->lchild->val)
        return false;
    else if(root->rchild!=NULL&&root->val>=root->rchild->val)
        return false;
    else if(root->lchild==NULL&&root->rchild==NULL)
        return true;
    else
        return isBST(root->lchild)&&isBST(root->rchild);
}

int main()
{
    TreeNode *root;
    BuildTree(root);
    if(isBST(root))
        cout<<"true"<<endl;
    else
        cout<<"false"<<endl;
    return 0;
}

1303: 判断树的子树

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

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

输出

若t是s的子树 ,输出"yes" , 否则输出 “no”.

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

typedef struct TreeNode{
   int val;
   TreeNode *lchild;
   TreeNode *rchild;
};

bool ok=0;//用来判断是否已经比较完成

bool isSame(TreeNode* T1,TreeNode* T2){
    if(T1==NULL&&T2==NULL)
        return true;
    if(!T1&&T2||T1&&!T2||T1->val!=T2->val)
        return false;
    return isSame(T1->lchild,T2->lchild)&&isSame(T1->rchild,T2->rchild);
}

void subTree(TreeNode* T1,TreeNode* T2)
{
    if(T1==NULL||ok)
        return;
    if(T1->val==T2->val)//结点相等,仔细遍历
        ok=isSame(T1,T2);
    subTree(T1->lchild,T2);//结点不相等,继续遍历
    subTree(T1->rchild,T2);
}

void BuildTree(TreeNode* &T){//按照先序遍历建树
    int key;
    cin>>key;
    if(key==-1){
        T=NULL;
        return;
    }
    else{
        T = new TreeNode;
        T->val=key;
        T->lchild=NULL;
        T->rchild=NULL;
        BuildTree(T->lchild);
        BuildTree(T->rchild);
    }
}


int main()
{
    TreeNode *T1=NULL,*T2=NULL;
    BuildTree(T1),BuildTree(T2);
    subTree(T1,T2);
    if(ok)
        cout<<"yes"<<endl;
    else
        cout<<"no"<<endl;
    return 0;
}

1285: 判定图中是否有环

题目描述

PIPI有一个有向图,他想让你判断图中是否有环,数据结构基础扎实的你能不能帮帮PIPI呢?

解析

利用拓扑排序,进行环的查找,先建立邻接表,存在环的话,就存在度不为0的点,最后排序出来的节点数小于节点总数。

输入

第一行两个整数n ,m 代表图中的结点数量和边的数量。
接下来m行,每行输入两个整数 a b 代表a有一条指向b的单向边。
输入所有数据在[1,20]以内。

输出

若图中有环,输出"yes",否则输出"no".

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

const int MaxSize=21;
int a[MaxSize],b[MaxSize];

typedef struct ArcNode{//链接点
    int adjvex;
    ArcNode* next;
}ArcNode;

typedef struct VNode{
    int data;
    ArcNode* firstarc;
};

typedef struct LGraph{
    VNode vexlist[MaxSize];
    int arcnum,vexnum;//边数,和节点数;
};

void create(LGraph& G,int n,int m)
{
    G.arcnum=m,G.vexnum=n;
    for(int i=1;i<=n;i++){
        G.vexlist[i].data=i;
        G.vexlist[i].firstarc=NULL;
    }
    for(int i=0;i<m;i++){
        int s=a[i],t=b[i];
        ArcNode* p = new ArcNode;
        p->adjvex=t;
        p->next=G.vexlist[i].firstarc;//头插法
        G.vexlist[i].firstarc=p;
    }
}
bool Judge(LGraph G)
{
    queue<int> q;
    int cnt=0;
    int indegree[MaxSize]={0};
    for(int i=1;i<=G.vexnum;i++){
        ArcNode* p = G.vexlist[i].firstarc;
        while(p){
            indegree[p->adjvex]++;//节点入度++
            p=p->next;
        }
    }
    for(int i=1;i<=G.vexnum;i++){
        if(indegree[i]==0)
            q.push(i);
    }
    while(!q.empty()){
        int now=q.front();
        q.pop();
        cnt++;//计数器
        for(ArcNode* p=G.vexlist[now].firstarc;p;p=p->next){
            int u=p->adjvex;
            if(!(--indegree[u])) q.push(u);//若结点入度变为0后,当前结点入队
        }
    }
    if(cnt<G.vexnum) return false;
    return true;
}

int main()
{
    int n,m;
    cin>>n>>m;
    for(int i=0;i<m;i++)
        cin>>a[i]>>b[i];
    LGraph G;
    create(G,n,m);
    if(!Judge(G))
        cout<<"yes"<<endl;
    else
        cout<<"no"<<endl;
    return 0;
}

1361: 为二叉排序树排序

题目描述

现在给你两棵二叉排序树,要求你对两棵二叉排序树的中的所有元素进行升序排序。

解析

先建树,然后对两棵树按照中序遍历进行遍历,得到两个递增序列,最后按照归并排序进行合并即可。

输入

输入两行,每一行按照先序输入一棵二叉排序树,其中空节点用 -1 表示(二叉树的结点不超过2000)。

输出

输出升序排序之后的结果。

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

typedef struct TreeNode{
    int val;
    TreeNode* left,*right;
};
vector<int> ans[3];

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

void DFS(TreeNode* root,int id)
{
    if(!root)return;
    DFS(root->left,id);
    ans[id].push_back(root->val);
    DFS(root->right,id);
}

void solve(TreeNode* root1,TreeNode* root2)
{
    DFS(root1,0);
    DFS(root2,1);
    //合并两个序列
    int i=0,j=0;
    while(i<ans[0].size() && j<ans[1].size()){
        if(ans[0][i]<ans[1][j]){
            ans[2].push_back(ans[0][i++]);
        }else if(ans[0][i]>ans[1][j]){
            ans[2].push_back(ans[1][j++]);
        }else{
            ans[2].push_back(ans[0][i++]);
            ans[2].push_back(ans[1][j++]);
        }
    }
    while(i<ans[0].size())
        ans[2].push_back(ans[0][i++]);
    while(j<ans[1].size())
        ans[2].push_back(ans[1][j++]);
    return;
}

int main()
{
    TreeNode *root1,*root2;
    BuildTree(root1);
    BuildTree(root2);
    solve(root1,root2);
    for(int i=0;i<ans[2].size();i++)
        printf("%d ",ans[2][i]);
    return 0;
}

1089: 简单迷宫问题

题目描述

PIPI定义了一个二维数组:
int maze[5][5] = {
0, 1, 0, 0, 0,
0, 1, 0, 1, 0,
0, 0, 0, 0, 0,
0, 1, 1, 1, 0,
0, 0, 0, 1, 0,
};
它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,请找出从左上角到右下角的最短路线。

解析

利用BFS进行路径搜索,重点在与记录最短路径节点,定义一个结构体,去存储路径节点,然后利用递归遍历去输出路径节点(DFS)

输入

仅一组测试用例。
一个5 × 5的二维数组,表示一个迷宫。数据保证有唯一解。

输出

左上角到右下角的最短路径,格式如样例所示。

样例输入
0 1 0 0 0
0 1 0 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0
样例输出
(0, 0)
(1, 0)
(2, 0)
(2, 1)
(2, 2)
(2, 3)
(2, 4)
(3, 4)
(4, 4)
提示

简单轻松的搜索入门~

#include<bits/stdc++.h>
using namespace std;
int dir[4][2]={{1,0},{0,1},{-1,0},{0,-1}};//定义方向数组
int n=5,m=5;
int mp[5][5],vis[5][5];
typedef struct Node{
    int x,y;
};
struct Road{//记录路径节点
    int x=-1,y=-1;//初始为-1,-1
}road[10][10];

void DFS(int x,int y)
{
    if(x==-1 && y==-1)return;
    DFS(road[x][y].x, road[x][y].y);
    printf("(%d, %d)\n",x,y);
}

void BFS()
{
    memset(vis,0,sizeof(vis));
    Node s;
    s.x=0,s.y=0;
    vis[s.x][s.y]=1;
    queue<Node> q;
    q.push(s);
    while(!q.empty()){
        Node now=q.front();
        q.pop();
        if(now.x==m-1&&now.y==n-1){
            DFS(m-1,m-1);
            return;
        }
        for(int i=0;i<4;i++){
            int tx=now.x+dir[i][0];
            int ty=now.y+dir[i][1];
            if(tx>=0&&ty<m&&ty>=0&&ty<n&&!vis[tx][ty]&&!mp[tx][ty]){
               q.push({tx,ty});
               vis[tx][ty]=1;
               road[tx][ty].x=now.x;
               road[tx][ty].y=now.y;
            }
        }
    }
}

int main()
{
    for(int i=0;i<5;i++)
        for(int j=0;j<5;j++)
          cin>>mp[i][j];
    BFS();
    return 0;
}

1403: 八大排序——堆排序

题目描述

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

输入

输入的第一行包含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;
//利用堆结构进行排序的方法,它只需要一个记录大小的辅助空间,每个待排序的记录仅需要占有一个存储空间
int a[100010];

void HeapAdjust(int a[],int p,int len)
{
    int tmp=a[p];
    for(int i=2*p;i<=len;i*=2){
        if(i<len&&a[i]<a[i+1])i++;
        if(a[i]<=tmp)break;
        a[p]=a[i];
        p=i;
    }
    a[p]=tmp;//插入最终位置
}

void HeapSort(int a[],int len)
{
    for(int i=len/2;i>0;i--){//从最后一个分支节点开始调整
        HeapAdjust(a,i,len);
    }
    for(int i=len;i>1;i--){
        swap(a[i],a[1]);
        HeapAdjust(a,1,i-1);
    }
}

int main()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    HeapSort(a,n);
    for(int i=1;i<=n;i++)
        printf("%d ",a[i]);
    return 0;
}

1405: 八大排序——快速排序

题目描述

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

输入

输入的第一行包含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;

int a[100010];

int Partition(int a[],int l,int r)
{
    int key=a[l];
    while(l<r){
        while(l<r&&a[r]>=key)--r;
        a[l]=a[r];
        while(l<r&&a[l]<=key)++l;
        a[r]=a[l];
    }
    a[l]=key;
    return l;
}

void QuickSort(int a[],int l,int r)
{
    if(l>=r)return;
    int pov=Partition(a,l,r);
    QuickSort(a,l,pov-1);
    QuickSort(a,pov+1,r);
}

int main()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    QuickSort(a,1,n);
    for(int i=1;i<=n;i++)
        printf("%d ",a[i]);
    return 0;
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值