挑战程序设计竞赛2-算法和数据结构

先把基础搞好,所以把这本书刷一遍!!!

文章目录

      • 第二章
        • 2.5 入门问题
      • 第三章 初等排序
        • 3.2 插入排序法
        • 3.3 冒泡排序法
        • 3.4 选择排序法
      • 第四章 数据结构
        • 4.2 栈 逆波兰表达式
        • 4.3 队列 任务调度模型
        • 4.4 链表
        • 4.6 计算面积
      • 第五章 搜索
        • 5.2 线性搜索
        • 5.3 二分搜索
        • 5.4 散列法 哈希表的实现
      • 第六章 递归和分治法
        • 6.2 穷举搜索
      • 第七章 高等排序
        • 7.1 归并排序
      • 第八章 树
        • 8.2 有根树的表达
        • 8.3 二叉树的表达
        • 8.4 树的遍历
      • 第十一章 动态规划法
        • 斐波那契数列
      • 第十二章 图
        • 12.4广度优先搜索
      • 第十七章 动态规划法
        • 17.3 最长递增子序列

第二章

2.5 入门问题

ALDS1_1_D:Maximum Profit

#include
using namespace std;
int n,ma=INT_MIN,mi=INT_MAX,num;//以前没注意,
//可以直接设置int的最大值和最小值为INT_MAX和INT_MIN
int main()
{
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>num;
        ma=max(ma,num-mi);//更新差值最大值
        mi=min(mi,num);//一直更新i之前的最小值
    }
    cout<<ma<<"\n";
}

第三章 初等排序

3.2 插入排序法

ALDS1_1_A:Insertion Sort

#include
using namespace std;
const int maxn=100+10;
int n,arr[maxn];
int main()
{
    cin>>n;
    for(int i=0;i<n;i++) cin>>arr[i];
    for(int i=0;i<n;i++){
        int v=arr[i];//需要排序的数
        int j=i-1;
        while(j>=0&&arr[j]>v){//将比v大的数字都向后平移一位
            arr[j+1]=arr[j];
            j--;
        }
        arr[j+1]=v;//将v插入到比v都大的数字向后平移一位以后留出来的那个空隙里
        for(int i=0;i<n;i++){
            if(i) cout<<" "<<arr[i];
            else cout<<arr[i];
        }cout<<"\n";
    }
}

3.3 冒泡排序法

ALDS1_2_A:Bubble Sort

#include
using namespace std;
const int maxn=100+10;
int n,arr[maxn],cnt=0;
int main()
{
    cin>>n;
    for(int i=0;i<n;i++) cin>>arr[i];
    bool flag=1;
    for(int i=0;flag;i++){
        flag=0;//如果在一轮循环中没有交换,说明已经排序完毕,就终止循环
        for(int j=n-1;j>i;j--){//从后往前排
            if(arr[j-1]>arr[j]){
                flag=1;
                swap(arr[j],arr[j-1]);
                cnt++;
            }
        }
    }
    for(int i=0;i<n;i++){
        if(i) cout<<" ";
        cout<<arr[i];
    }
    cout<<"\n"<<cnt<<"\n";
}

3.4 选择排序法

ALDS1_2_B:Selection Sort

//方法1
#include
using namespace std;
const int maxn=100+10;
int n,arr[maxn],cnt=0;
int main()
{
    cin>>n;
    for(int i=0;i<n;i++) cin>>arr[i];
    for(int i=0;i<n;i++){
        int minj=i;
        for(int j=i;j<n;j++){//记录未排序序列中的最小值的下标
            if(arr[j]<arr[minj]){
                minj=j;
            }
        }
        if(i!=minj){
            cnt++;
            swap(arr[i],arr[minj]);
        }
    }
    for(int i=0;i<n;i++){
        if(i) cout<<" ";
        cout<<arr[i];
    }
    cout<<"\n"<<cnt<<"\n";
}
//方法2
#include
using namespace std;
const int maxn=100+10;
int n,arr[maxn],cnt=0;
int main()
{
    cin>>n;
    for(int i=0;i<n;i++) cin>>arr[i];
    for(int i=0;i<n;i++){
        int minj=i;
        minj=min_element(arr+i,arr+n)-arr;//min_element返回的是数组最小值位置指针,获取最小值用*min_element(begin,end),获取最小值下标用min_element(begin,end)-arr
        if(i!=minj){
            cnt++;
            swap(arr[i],arr[minj]);
        }
    }
    for(int i=0;i<n;i++){
        if(i) cout<<" ";
        cout<<arr[i];
    }
    cout<<"\n"<<cnt<<"\n";
}

第四章 数据结构

4.2 栈 逆波兰表达式

ALDS1_3_A:Stack

#include
using namespace std;
int main()
{
    stack<int>st;
    char s[100];
    while(cin>>s){
        int a,b;
        if(s[0]=='+'){
            a=st.top();st.pop();
            b=st.top();st.pop();
            st.push(b+a);
        }else if(s[0]=='-'){
            a=st.top();st.pop();
            b=st.top();st.pop();
            st.push(b-a);
        }else if(s[0]=='*'){
            a=st.top();st.pop();
            b=st.top();st.pop();
            st.push(b*a);
        }else st.push(atoi(s));//atoi()用来将字符串形式的数字转换为整形数值
    }
    cout<<st.top()<<"\n";
}

4.3 队列 任务调度模型

ALDS1_3_B:Queue

#include
using namespace std;
struct node {
    char name[100];
    int t;
};
int main() {
    int n,q,t;
    scanf("%d%d",&n,&q);
    queue<node>qu;//可以用queue >qu代替
    for(int i=0; i<n; i++) {
        node N;
        scanf("%s%d",N.name,&N.t);
        qu.push(N);
    }
    int sum=0;
    while(!qu.empty()) {
        node this_node=qu.front();
        qu.pop();
        sum+=min(this_node.t,q);
        if(this_node.t<=q) {
            printf("%s %d\n",this_node.name,sum);
        } else {
            this_node.t-=q;
            qu.push(this_node);
        }
    }
}

4.4 链表

ALDS1_3_C:Doubly Linked List

#include
using namespace std;
int main()
{
    list<int>lst;
    int num;char c[20];
    int n;scanf("%d",&n);
    while(n--){
        scanf("%s",c);
        if(c[0]=='i') {scanf("%d",&num);lst.push_front(num);}
        else if(c[6]=='F') lst.pop_front();//deleteFirst
        else if(c[6]=='L') lst.pop_back();//deleteLast
        else if(c[0]=='d'){
            scanf("%d",&num);
            for(list<int>::iterator it=lst.begin();it!=lst.end();it++){
                if(*it==num) {
                    lst.erase(it);break;
                }
            }
        }
    }
    int i=0;
    for(list<int>::iterator it=lst.begin();it!=lst.end();it++) {
        if(i++) printf(" ");
        printf("%d",*it);
    }
    printf("\n");
    return 0;
}
//不用STL的
#include
using namespace std;
struct Node {
    int key;
    Node *prev,*next;
};
Node *nil;
void init() {
    nil=(Node *)malloc(sizeof(Node));
    nil->next=nil;
    nil->prev=nil;
}
Node * listSearch(int key) {
    Node *cur=nil->next;//从头节点后面的元素开始访问
    while(cur!=nil&&cur->key!=key) {
        cur=cur->next;
    }
    return cur;
}
void printList() {
    Node *cur=nil->next;
    int isf=0;
    while(1) {
        if(cur==nil) break;
        if(isf++>0) printf(" ");
        printf("%d",cur->key);
        cur=cur->next;
    }
    printf("\n");
}
void deleteNode(Node *t) {
    if(t==nil) return ;//t为头结点时不做处理
    t->prev->next=t->next;
    t->next->prev=t->prev;
    free(t);
}
void deleteFirst() {
    deleteNode(nil->next);
}
void deleteLast() {
    deleteNode(nil->prev);
}
void deleteKey(int key){
    deleteNode(listSearch(key));
}
void insert(int key){
    Node *x=(Node *)malloc(sizeof(Node));
    x->key=key;
    //在头节点后添加元素
    x->next=nil->next;
    x->next->prev=x;
    nil->next=x;
    x->prev=nil;
}
int main() {
    char c[20];
    int n,num;
    init();
    scanf("%d",&n);
    while(n--){
        scanf("%s",c);
        if(c[0]=='i') {scanf("%d",&num);insert(num);}
        else if(c[6]=='F') deleteFirst();
        else if(c[6]=='L') deleteLast();
        else if(c[0]=='d'){
            scanf("%d",&num);
            deleteKey(num);
        }
    }
    printList();
}

4.6 计算面积

ALDS1_3_D:Areas on the Cross-Section Diagram
这题就是求所有积水区域的总面积和有多少各个积水区域的面积分别是多少。

#include
using namespace std;
int main()
{
    stack<int>st;//用来存储\的位置j,用来求单对\/形成的面积(相当于一层一层的算)
    //单对\/形成的面积是i-j
    stack<pair<int,int> >area;
    char c;
    int sum=0;
    for(int i=0;cin>>c;i++){
        if(c=='\\') st.push(i);
        else if(c=='/'&&st.size()>0){
            int j=st.top();st.pop();
            sum+=(i-j);//单对\/形成的面积是i-j
            int a=i-j;
            while(area.size()>0&&area.top().first>j){//如果当前匹配到的一对\/的左边的\的位置比已经存到area中的那个区域面积最左边的\的位置小,
            //说明需要合并
                a+=area.top().second;area.pop();
            }
            area.push(make_pair(j,a));//合并好的push进去
        }
    }
    vector<int>ans;
    while(!area.empty()){
        ans.push_back(area.top().second);
        area.pop();
    }
    reverse(ans.begin(),ans.end());
    cout<<sum<<"\n"<<ans.size();
    for(auto i:ans){
        cout<<" "<<i;
    }
    cout<<"\n";
}

第五章 搜索

5.2 线性搜索

ALDS1_4_A:Linear Search

#include
using namespace std;
const int maxn=1e4+10;
int main()
{
    int n,q,S[maxn],key;
    scanf("%d",&n);
    for(int i=0;i<n;i++) scanf("%d",&S[i]);
    sort(S,S+n);
    scanf("%d",&q);
    int cnt=0;
    for(int i=0;i<q;i++) {
        scanf("%d",&key);
        if(*lower_bound(S,S+n,key)==key) cnt++;
    }
    printf("%d\n",cnt);
}

5.3 二分搜索

ALDS1_4_B Binary Search

#include
using namespace std;
vector<int>S;
int bisearch(int n,int a){
    int left=0,right=n;
    while(left<right){
        int mid=left+(right-left)/2;
        if(a==S[mid]) return 1;
        else if(a<S[mid]) right=mid;
        else left=mid+1;
    }
    return 0;
}
int main()
{
    int n,a,q,cnt=0;
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%d",&a);
        S.push_back(a);
    }
    scanf("%d",&q);
    for(int i=0;i<q;i++){
        scanf("%d",&a);
        cnt+=bisearch(n,a);
    }
    printf("%d\n",cnt);
}

5.4 散列法 哈希表的实现

ALDS1_4_C:Dictionary

第六章 递归和分治法

6.2 穷举搜索

ALDS1_5_A:Exhaustive Search

#include
using namespace std;
const int maxn=20+5;
int n,num,arr[maxn],q,vis[400010];
void dfs(int cur,int sum){//再vis数组中标记arr数组中的数所有组合方式产生的数字和
    if(cur==n) return ;
    vis[sum]=1;
    dfs(cur+1,sum+arr[cur+1]);
    dfs(cur+1,sum);
}
int main()
{
    cin>>n;
    for(int i=0;i<n;i++) cin>>arr[i];
    cin>>q;
    dfs(-1,0);
    while(q--){
        cin>>num;
        if(vis[num]) cout<<"yes\n";
        else cout<<"no\n";
    }
}
#include
using namespace std;
const int maxn=20+5;
int n,arr[maxn],q,num;
bool solve(int idx,int m){//表示再arr数组下标从idx往后能不能组成m
    if(m==0) return true;
    if(idx==n) return false;//这两个if顺序不能反,注意边界
    return solve(idx+1,m)||solve(idx+1,m-arr[idx]);
}
int main()
{
    cin>>n;
    for(int i=0;i<n;i++) cin>>arr[i];
    cin>>q;
    while(q--){
        cin>>num;
        if(solve(0,num)) cout<<"yes\n";
        else cout<<"no\n";
    }
}

第七章 高等排序

7.1 归并排序

ALDS1_5_B:Merge Sort

#include
using namespace std;
#define LL long long
#define INF INT_MAX
const int maxn=5e5+10;
int L[maxn/2+2],R[maxn/2+2];
int cnt;
void merge(int A[],int n,int left,int mid,int right){
    int n1=mid-left;
    int n2=right-mid;
    for(int i=0;i<n1;i++) L[i]=A[left+i];
    for(int i=0;i<n2;i++) R[i]=A[mid+i];
    L[n1]=R[n2]=INF;
    int i=0,j=0;
    for(int k=left;k<right;k++){
        cnt++;//记录比较次数
        if(L[i]<=R[j]) A[k]=L[i++];
        else A[k]=R[j++];
    }
}
void mergeSort(int A[],int n,int left,int right){
    if(left+1<right){
        int mid=(left+right)/2;
        mergeSort(A,n,left,mid);
        mergeSort(A,n,mid,right);
        merge(A,n,left,mid,right);
    }
 
}
int main()
{
    int A[maxn],n;
    cnt=0;
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>A[i];
    }
    mergeSort(A,n,0,n);
    for(int i=0;i<n;i++){
        if(i) cout<<" ";
        cout<<A[i];
    }cout<<endl;
    cout<<cnt<<endl;
}

第八章 树

8.2 有根树的表达

ALDS1_7_A:Rooted Trees
用的是左子右兄弟表示法(left-child right-sibling representation)表示树

#include
using namespace std;
#define NIL -1
const int MAX=1e5+10;
struct Node{
    int p,l,r;//parent,left,right
    Node(int p=NIL,int l=NIL,int r=NIL){
        this->p=p;this->l=l;this->r=r;
    }
}T[MAX];
int n,D[MAX];//D是深度,O(n)递归求
void rec(int cur,int dep){
    D[cur]=dep;
    if(T[cur].l!=NIL) rec(T[cur].l,dep+1);
    if(T[cur].r!=NIL) rec(T[cur].r,dep);
}
void print(int cur){
    cout<<"node "<<cur<<": parent = "<<T[cur].p<<", "<<"depth = "<<D[cur]<<", ";
    if(T[cur].p==NIL) cout<<"root, [";
    else if(T[cur].l==NIL) cout<<"leaf, [";
    else cout<<"internal node, [";
    for(int i=0,c=T[cur].l;c!=NIL;c=T[c].r,i++){
        if(i) cout<<", ";
        cout<<c;
    }
    cout<<"]\n";
}
int main()
{
    int id,k,v;
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>id>>k;
        int rr;
        for(int j=0;j<k;j++){
            cin>>v;
            if(j==0) T[id].l=v;
            else T[rr].r=v;
            rr=v;
            T[v].p=id;
        }
    }
    int root;
    for(int i=0;i<n;i++) if(T[i].p==NIL) {root=i;break;}//找根节点
    rec(root,0);
    for(int i=0;i<n;i++) print(i);
}

8.3 二叉树的表达

ALDS1_7_B:Binary Trees

#include
#define NIL -1
using namespace std;
const int MAX=30;
int n,D[MAX],H[MAX];
struct Node{
    int p,l,r;//parent,left,right
    Node(int p=NIL){this->p=p;}
}T[MAX];
void setDepth(int cur,int dep){
    D[cur]=dep;
    if(T[cur].l!=NIL) setDepth(T[cur].l,dep+1);
    if(T[cur].r!=NIL) setDepth(T[cur].r,dep+1);
}
int setHeight(int cur){
    int hl=0,hr=0;
    if(T[cur].l!=NIL) hl=setHeight(T[cur].l)+1;
    if(T[cur].r!=NIL) hr=setHeight(T[cur].r)+1;
    return H[cur]=max(hl,hr);
}
int getSibling(int cur){
    if(T[cur].p==NIL) return NIL;
    if(T[T[cur].p].l!=cur&&T[T[cur].p].l!=NIL) return T[T[cur].p].l;
    if(T[T[cur].p].r!=cur&&T[T[cur].p].r!=NIL) return T[T[cur].p].r;
    return NIL;
}
int getDegree(int cur){
    int deg=0;
    if(T[cur].l!=NIL) deg++;
    if(T[cur].r!=NIL) deg++;
    return deg;
}
void print(int cur){
    cout<<"node "<<cur<<": parent = "<<T[cur].p<<", sibling = "<<getSibling(cur)<<", degree = ";
    cout<<getDegree(cur)<<", depth = "<<D[cur]<<", height = "<<H[cur]<<", ";
    if(T[cur].p==NIL) cout<<"root\n";
    else if(T[cur].l==NIL&&T[cur].r==NIL) cout<<"leaf\n";
    else cout<<"internal node\n";
}
int main()
{
    int id,left,right;
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>id>>left>>right;
        T[id].l=left;
        T[id].r=right;
        if(left!=NIL) T[left].p=id;//判断一下,防止数组越界
        if(right!=NIL) T[right].p=id;
    }
    int root;
    for(int i=0;i<n;i++) if(T[i].p==NIL){root=i;break;}
    setDepth(root,0);
    setHeight(root);
    for(int i=0;i<n;i++) print(i);
}

8.4 树的遍历

ALDS1_7_C:Tree Walk

#include
#define NIL -1
using namespace std;
const int maxn=30;
struct Node{
    int p,l,r;
    Node(int p=NIL){this->p=p;}
}T[maxn];
void Preorder(int cur){
    if(cur==NIL) return ;
    cout<<" "<<cur;
    Preorder(T[cur].l);
    Preorder(T[cur].r);
}
void Inorder(int cur){
    if(cur==NIL) return ;
    Inorder(T[cur].l);
    cout<<" "<<cur;
    Inorder(T[cur].r);
}
void Postorder(int cur){
    if(cur==NIL) return ;
    Postorder(T[cur].l);
    Postorder(T[cur].r);
    cout<<" "<<cur;
}
int main()
{
    int n,id,ll,rr;
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>id>>ll>>rr;
        T[id].l=ll;
        T[id].r=rr;
        if(ll!=NIL) T[ll].p=id;
        if(rr!=NIL) T[rr].p=id;
    }
    int root;
    for(int i=0;i<n;i++) if(T[i].p==NIL) {root=i;break;}
    cout<<"Preorder\n";
    Preorder(root);
    cout<<"\nInorder\n";
    Inorder(root);
    cout<<"\nPostorder\n";
    Postorder(root);
    cout<<"\n";
}

第十一章 动态规划法

斐波那契数列

ALDS1_10_A:Fibonacci Number


第十二章 图

12.4广度优先搜索

ALDS1_11_C:Breadth First Search

#include
using namespace std;
const int maxn=100+10;
int n,G[maxn][maxn],dis[maxn],vis[maxn];
void bfs(){
    memset(dis,0,sizeof dis);
    memset(vis,0,sizeof vis);
    queue<int>que;
    que.push(1);vis[1]=1;dis[1]=0;
    while(!que.empty()){
        int cur=que.front();que.pop();
        for(int i=1;i<=n;i++){
            if(G[cur][i]&&!vis[i]){
                que.push(i);
                dis[i]=dis[cur]+1;
                vis[i]=1;
            }
        }
    }
}
int main()
{
    cin>>n;
    for(int i=0;i<n;i++){
        int u,k;cin>>u>>k;
        for(int j=0;j<k;j++){
            int v;cin>>v;
            G[u][v]=1;
        }
    }
    bfs();
    for(int i=1;i<=n;i++) if(!vis[i]) dis[i]=-1;//在bfs完以后还没到达的点到1点的距离设置为-1
    for(int i=1;i<=n;i++) cout<<i<<" "<<dis[i]<<"\n";
}
//用邻接表写
#include
using namespace std;
const int maxn=100+10;
int n,dis[maxn],vis[maxn];
vector<int>G[maxn];
void bfs(){
    memset(dis,0,sizeof dis);
    memset(vis,0,sizeof vis);
    queue<int>que;
    que.push(1);vis[1]=1;dis[1]=0;
    while(!que.empty()){
        int cur=que.front();que.pop();
        for(auto i:G[cur]){
            if(!vis[i]){
                que.push(i);
                dis[i]=dis[cur]+1;
                vis[i]=1;
            }
        }
    }
}
int main()
{
    cin>>n;
    for(int i=0;i<n;i++){
        int u,k;cin>>u>>k;
        for(int j=0;j<k;j++){
            int v;cin>>v;
            G[u].push_back(v);
        }
    }
    bfs();
    for(int i=1;i<=n;i++) if(!vis[i]) dis[i]=-1;//在bfs完以后还没到达的点到1点的距离设置为-1
    for(int i=1;i<=n;i++) cout<<i<<" "<<dis[i]<<"\n";
}

第十七章 动态规划法

17.3 最长递增子序列

DPL_1_D:Longest Increasing Subsequence

lower_bound(arr,arr+n,x)是在arr数组(已排序)中二分查找第一个大于等于x的数的位置指针

#include
using namespace std;
const int maxn=1e5+10;
int arr[maxn],n,L[maxn];
const int inf=0x3f3f3f3f;
int main()
{
    memset(L,inf,sizeof L);
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>arr[i];
        *lower_bound(L,L+n,arr[i])=arr[i];
    }
    cout<<lower_bound(L,L+n,inf)-L<<"\n";
}

你可能感兴趣的:(挑战程序设计竞赛)