第四次上机赛标程

  这次渣诚来写解题报告,我只放我的标程;大量与书中风格不同的代码请慎入。

  A. 二叉树的最短路

  利用二叉树的数学性质。

#include<cstdio>
using namespace std;
int main()
{
    int n,x,y;
    scanf("%d",&n);
    while(n--)
    {
        scanf("%d%d",&x,&y);
        int ans=0;
        while(x!=y)
        {
            x>y?x>>=1:y>>=1;
            ++ans;
        }
        printf("%d\n",ans);
    }
}

  B. 同构二叉树

  配套的学习指导上有源代码。

#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;
const int MAXN=1005;
struct BTNode
{
    char data[10];
    BTNode *lchild,*rchild;
};
char str[MAXN];
void CreateBTNode(BTNode *&b)
{
    BTNode *St[MAXN],*p;
    int top=-1,k,l=strlen(str);
    b=NULL;
    for(int i=0; i<l; ++i)
        switch(str[i])
        {
        case '(':
            St[++top]=p;
            k=1;
            break;
        case ')':
            --top;
            break;
        case ',':
            k=2;
            break;
        default:
            p=(BTNode *)malloc(sizeof(BTNode));
            int j=0;
            while(i<l&&str[i]!='('&&str[i]!=')'&&str[i]!=',')
                p->data[j++]=str[i++];
            --i;
            p->data[j]='\0';
            p->lchild=p->rchild=NULL;
            if(!b)
                b=p;
            else
                switch(k)
                {
                case 1:
                    St[top]->lchild=p;
                    break;
                case 2:
                    St[top]->rchild=p;
                    break;
                }
        }
}
bool Symm(BTNode *b1,BTNode *b2)
{
    if(!b1&&!b2)
        return true;
    if(!b1||!b2)
        return false;
    else
        return Symm(b1->lchild,b2->lchild)&&Symm(b1->rchild,b2->rchild);
}
bool Symmtree(BTNode *b)
{
    if(!b)
        return true;
    return Symm(b->lchild,b->rchild);
}
void DestroyBT(BTNode *&b)
{
    if(b->lchild)
        DestroyBT(b->lchild);
    if(b->rchild)
        DestroyBT(b->rchild);
    free(b);
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%s",str);
        BTNode *b;
        CreateBTNode(b);
        puts(Symmtree(b)?"YES":"NO");
        DestroyBT(b);
    }
}

  C. Papers

  哈夫曼树,扔板子就行了。其实不需要建一棵树出来,哈夫曼树的本质是贪心,故而可以建一个堆或用一个优先队列来搞。我写了建哈夫曼树和优先队列两个版本。

#include<cstdio>
#include<cstring>
using namespace std;
const int MAXN=5005;
const int INF=0x3f3f3f3f;
struct HuffmanTree
{
    int parent[MAXN<<1];
    int lchild[MAXN<<1];
    int rchild[MAXN<<1];
    int weight[MAXN<<1];
} ht;
int n;
void CreateHT()
{
    int lnode,rnode,min1,min2;
    memset(ht.parent,0xff,sizeof(ht.parent));
    memset(ht.lchild,0xff,sizeof(ht.lchild));
    memset(ht.rchild,0xff,sizeof(ht.rchild));
    for(int i=n; i<(n<<1)-1; ++i)
    {
        min1=min2=INF;
        lnode=rnode=-1;
        for(int j=0; j<i; ++j)
            if(!~ht.parent[j])
            {
                if(ht.weight[j]<min1)
                {
                    min2=min1;
                    rnode=lnode;
                    min1=ht.weight[j];
                    lnode=j;
                }
                else if(ht.weight[j]<min2)
                {
                    min2=ht.weight[j];
                    rnode=j;
                }
            }
        ht.weight[i]=ht.weight[lnode]+ht.weight[rnode];
        ht.lchild[i]=lnode;
        ht.rchild[i]=rnode;
        ht.parent[lnode]=ht.parent[rnode]=i;
    }
}
int main()
{
    while(~scanf("%d",&n))
    {
        for(int i=0; i<n; ++i)
            scanf("%d",&ht.weight[i]);
        CreateHT();
        int ans=0;
        for(int i=n; i<(n<<1)-1; ++i)
            ans+=ht.weight[i];
        printf("%d\n",ans);
    }
}
#include<cstdio>
#include<vector>
#include<queue>
using namespace std;
int main()
{
    int n,x;
    while(~scanf("%d",&n))
    {
        priority_queue<int,vector<int>,greater<int> > pq;
        while(n--)
        {
            scanf("%d",&x);
            pq.push(x);
        }
        int ans=0;
        while(pq.size()>1)
        {
            int x=pq.top();
            pq.pop();
            int y=pq.top();
            pq.pop();
            ans+=x+y;
            pq.push(x+y);
        }
        printf("%d\n",ans);
    }
}

  D. 电报编码

  哈夫曼编码,板子题。还是建哈夫曼树和优先队列两个版本。

#include<cstdio>
#include<cstring>
using namespace std;
const int MAXN=30;
const int MAXM=2005;
const int INF=0x3f3f3f3f;
struct HuffmanTree
{
    int parent[MAXN<<1];
    int lchild[MAXN<<1];
    int rchild[MAXN<<1];
    int weight[MAXN<<1];
} ht;
char str[MAXM];
int cnt[MAXN],n;
void CreateHT()
{
    int lnode,rnode,min1,min2;
    memset(ht.parent,0xff,sizeof(ht.parent));
    memset(ht.lchild,0xff,sizeof(ht.lchild));
    memset(ht.rchild,0xff,sizeof(ht.rchild));
    for(int i=n; i<(n<<1)-1; ++i)
    {
        min1=min2=INF;
        lnode=rnode=-1;
        for(int j=0; j<i; ++j)
            if(!~ht.parent[j])
            {
                if(ht.weight[j]<min1)
                {
                    min2=min1;
                    rnode=lnode;
                    min1=ht.weight[j];
                    lnode=j;
                }
                else if(ht.weight[j]<min2)
                {
                    min2=ht.weight[j];
                    rnode=j;
                }
            }
        ht.weight[i]=ht.weight[lnode]+ht.weight[rnode];
        ht.lchild[i]=lnode;
        ht.rchild[i]=rnode;
        ht.parent[lnode]=ht.parent[rnode]=i;
    }
}
int main()
{
    while(~scanf("%d",&n))
    {
        scanf("%s",str);
        int l=strlen(str);
        n=0;
        memset(cnt,0,sizeof(cnt));
        for(int i=0; i<l; ++i)
            ++cnt[str[i]-'a'];
        for(int i=0; i<26; ++i)
            if(cnt[i]>0)
                ht.weight[n++]=cnt[i];
        CreateHT();
        int ans=0;
        for(int i=n; i<(n<<1)-1; ++i)
            ans+=ht.weight[i];
        printf("%d\n",ans);
    }
}
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
const int MAXN=2005;
char str[MAXN];
int main()
{
    int n,cnt[30];
    while(~scanf("%d",&n))
    {
        scanf("%s",str);
        int l=strlen(str);
        memset(cnt,0,sizeof(cnt));
        for(int i=0; i<l; ++i)
            ++cnt[str[i]-'a'];
        priority_queue<int,vector<int>,greater<int> > pq;
        for(int i=0; i<26; ++i)
            if(cnt[i]>0)
                pq.push(cnt[i]);
        int ans=0;
        while(pq.size()>1)
        {
            int x=pq.top();
            pq.pop();
            int y=pq.top();
            pq.pop();
            ans+=x+y;
            pq.push(x+y);
        }
        printf("%d\n",ans);
    }
}

  E. Who Are My Friends?(Ⅰ)

  原意是考查并查集,不断合并朋友,最后看还剩下几组。事实上也可以用图论做,认为朋友之间存在一条边,则连通子图的个数就是答案,遍历一遍即可。

  这里想说一点是,书上对并查集的优化是根据树的层次合并以维护树高,保持每次查询的复杂度在O(logn);但最常用的优化方式是路径压缩,可以使查询复杂度接近O(1);实测时发现数据量小的时候几无差别,数据量大的时候路径压缩会更快一些。我这里放出三种标程,分别是路径压缩的并查集,维护树高的并查集,以及图论dfs。

#include<cstdio>
using namespace std;
const int MAXN=10005;
int u[MAXN];
void init()
{
    for(int i=0; i<MAXN; ++i)
        u[i]=i;
}
int find(int x)
{
    if(u[x]!=x)
        u[x]=find(u[x]);
    return u[x];
}
void merge(int x,int y)
{
    u[find(x)]=find(y);
}
int main()
{
    int n,m,a,b;
    while(~scanf("%d%d",&n,&m))
    {
        init();
        while(m--)
        {
            scanf("%d%d",&a,&b);
            merge(a,b);
        }
        int ans=0;
        for(int i=1; i<=n; ++i)
            if(find(i)==i)
                ++ans;
        printf("%d\n",ans);
    }
}
#include<cstdio>
using namespace std;
const int MAXN=10005;
int u[MAXN],r[MAXN];
void init()
{
    for(int i=0; i<MAXN; ++i)
    {
        u[i]=i;
        r[i]=0;
    }
}
int find(int x)
{
    if(u[x]!=x)
        return find(u[x]);
    return u[x];
}
void merge(int x,int y)
{
    x=find(x);
    y=find(y);
    if(r[x]>r[y])
        u[y]=x;
    else
    {
        u[x]=y;
        if(r[x]==r[y])
            ++r[y];
    }
}
int main()
{
    int n,m,a,b;
    while(~scanf("%d%d",&n,&m))
    {
        init();
        while(m--)
        {
            scanf("%d%d",&a,&b);
            merge(a,b);
        }
        int ans=0;
        for(int i=1; i<=n; ++i)
            if(find(i)==i)
                ++ans;
        printf("%d\n",ans);
    }
}
#include<cstdio>
#include<cstring>
using namespace std;
const int MAXN=10005;
const int MAXM=200005;
struct graph
{
    int head[MAXN];
    int to[MAXM];
    int next[MAXM];
    int tot;
    void init()
    {
        tot=0;
        memset(head,0xff,sizeof(head));
    }
    void add(int x,int y)
    {
        to[tot]=y;
        next[tot]=head[x];
        head[x]=tot++;
    }
} g;
bool vis[MAXN];
void dfs(int x)
{
    vis[x]=true;
    for(int i=g.head[x]; ~i; i=g.next[i])
    {
        int v=g.to[i];
        if(!vis[v])
            dfs(v);
    }
}
int main()
{
    int n,m,a,b;
    while(~scanf("%d%d",&n,&m))
    {
        g.init();
        memset(vis,false,sizeof(vis));
        while(m--)
        {
            scanf("%d%d",&a,&b);
            g.add(a,b);
            g.add(b,a);
        }
        int ans=0;
        for(int i=1; i<=n; ++i)
            if(!vis[i])
            {
                ++ans;
                dfs(i);
            }
        printf("%d\n",ans);
    }
}

  F. Who Are My Friends?(Ⅱ)

  跟上一题只有很小的区别。并查集合并,每次判断两个人是否在一个组。也可以用图论做,每次判断两个人是否在一个连通子图,方法是遍历时记录每个点所在连通子图的标号。还是三种姿势的代码。

#include<cstdio>
using namespace std;
const int MAXN=10005;
int u[MAXN];
void init()
{
    for(int i=0; i<MAXN; ++i)
        u[i]=i;
}
int find(int x)
{
    if(u[x]!=x)
        u[x]=find(u[x]);
    return u[x];
}
void merge(int x,int y)
{
    u[find(x)]=find(y);
}
bool query(int x,int y)
{
    return find(x)==find(y);
}
int main()
{
    int n,m,k,a,b;
    while(~scanf("%d%d%d",&n,&m,&k))
    {
        init();
        while(m--)
        {
            scanf("%d%d",&a,&b);
            merge(a,b);
        }
        while(k--)
        {
            scanf("%d%d",&a,&b);
            puts(query(a,b)?"Great!":"Pity...");
        }
    }
}
#include<cstdio>
using namespace std;
const int MAXN=10005;
int u[MAXN],r[MAXN];
void init()
{
    for(int i=0; i<MAXN; ++i)
    {
        u[i]=i;
        r[i]=0;
    }
}
int find(int x)
{
    if(u[x]!=x)
        return find(u[x]);
    return u[x];
}
void merge(int x,int y)
{
    x=find(x);
    y=find(y);
    if(r[x]>r[y])
        u[y]=x;
    else
    {
        u[x]=y;
        if(r[x]==r[y])
            ++r[y];
    }
}
bool query(int x,int y)
{
    return find(x)==find(y);
}
int main()
{
    int n,m,k,a,b;
    while(~scanf("%d%d%d",&n,&m,&k))
    {
        init();
        while(m--)
        {
            scanf("%d%d",&a,&b);
            merge(a,b);
        }
        while(k--)
        {
            scanf("%d%d",&a,&b);
            puts(query(a,b)?"Great!":"Pity...");
        }
    }
}
#include<cstdio>
#include<cstring>
using namespace std;
const int MAXN=10005;
const int MAXM=200005;
struct graph
{
    int head[MAXN];
    int to[MAXM];
    int next[MAXM];
    int tot;
    void init()
    {
        tot=0;
        memset(head,0xff,sizeof(head));
    }
    void add(int x,int y)
    {
        to[tot]=y;
        next[tot]=head[x];
        head[x]=tot++;
    }
} g;
int u[MAXN],cnt;
bool vis[MAXN];
void dfs(int x)
{
    u[x]=cnt;
    vis[x]=true;
    for(int i=g.head[x]; ~i; i=g.next[i])
    {
        int v=g.to[i];
        if(!vis[v])
            dfs(v);
    }
}
int main()
{
    int n,m,k,a,b;
    while(~scanf("%d%d%d",&n,&m,&k))
    {
        g.init();
        memset(vis,false,sizeof(vis));
        while(m--)
        {
            scanf("%d%d",&a,&b);
            g.add(a,b);
            g.add(b,a);
        }
        cnt=0;
        for(int i=1; i<=n; ++i)
            if(!vis[i])
            {
                ++cnt;
                dfs(i);
            }
        while(k--)
        {
            scanf("%d%d",&a,&b);
            puts(u[a]==u[b]?"Great!":"Pity...");
        }
    }
}

  G. 邻接矩阵转邻接表

  不能更水,根据两种结构的联系来做,不用建图。

#include<cstdio>
using namespace std;
int main()
{
    int m,n,x;
    while(~scanf("%d%d",&m,&n))
        for(int i=0; i<m; ++i)
        {
            printf("%d:",i);
            for(int j=0; j<m; ++j)
            {
                scanf("%d",&x);
                if(x>0)
                    printf("%d ",j);
            }
            putchar('\n');
        }
}

  因为题出得很水,所以这次上机结果看起来相当好……

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
很抱歉,我无法提供关于具体学校或课程的第四次上机内容。但是,我可以为您提供一些关于数据结构的基本知识和常见的上机题目类型。 数据结构是计算机科学中非常重要的一门课程,它研究如何组织和存储数据以及如何有效地操作和管理数据。第四次上机可能涉及以下内容之一: 1. 树和图的应用:树和图是常见的数据结构,可以用于解决各种实际问题,比如搜索、排序、最短路径等。在上机中,您可能需要实现树或图的基本操作,如插入、删除、遍历等。 2. 排序算法:排序是数据结构中的一个重要问题,常见的排序算法有冒泡排序、插入排序、选择排序、快速排序、归并排序等。您可能需要实现其中一个排序算法,并对给定的数据进行排序。 3. 查找算法:查找是另一个常见的问题,常见的查找算法有线性查找、二分查找、哈希查找等。您可能需要实现其中一个查找算法,并根据给定的条件查找特定的数据。 4. 动态规划:动态规划是一种解决最优化问题的方法,它将问题分解为子问题,并通过保存子问题的解来避免重复计算。您可能需要使用动态规划来解决给定的问题,并实现相应的算法。 以上只是一些可能的内容,具体的上机要求可能会根据课程教学大纲和教师的要求而有所不同。如果您有具体的问题或需要更详细的帮助,请提供更多信息,我将尽力回答您的问题。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值