北邮考研复试 | 机试 | 2014年北邮网研院机试(下午)

本文精选了算法竞赛中的典型题目并提供了解决方案,包括分数加法、最小堆验证、进程管理和网络数据传输等问题,涉及数据结构、算法设计等多个方面。

分数加法

题目来源

分数加法单独题解
OJ地址

题目描述

求2-a + 2-b,其中a和b均为正整数,结果请用最简分数表示。

输入格式

第一行为测试数据的组数T(1<=T<=400)。请注意,任意两组测试数据之间是相互独立的。
每组测试数据一行,包含两个整数a和b(2<=a,b<=20)。

输出格式

对于每组测试数据,在一行内输出结果,分子和分母用“/”隔开。

输入样例

    2
    2 4
    3 2

输出样例

    5/16
    3/8

AC代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    void toFraction(int a,int b,ll &u,ll &v){
        //return u/v
        u = (ll)(1<<a) + (ll)(1<<b) ;
        v = (ll)1<<(a+b) ;
        ll d =__gcd(u,v);
        u = u/d;
        v = v/d;
    }
    int main()
    {
        //cout << "Hello world!" << endl;
        int t,a,b;
        ll u,v;
        cin>>t;
        while(t--){
            cin>>a>>b;
            toFraction(a,b,u,v);
            cout<<u<<"/"<<v<<endl;
        }
        return 0;
    }
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    void toFraction(int a,int b,ll &u,ll &v){
        int fmin = (ll)min(a,b);
        int fmax = max(a,b);
        v<<=fmax;
        u<<=(fmax-fmin);
        u++;
    }
    int main()
    {
        //cout << "Hello world!" << endl;
        int t,a,b;
        cin>>t;
        while(t--){
            cin>>a>>b;
            ll u=1,v=1;
            toFraction(a,b,u,v);
            ll d = __gcd(u,v);
            //u/v
            cout<<u/d<<"/"<<v/d<<endl;
        }
        return 0;

最小堆

题目来源

单独题解
OJ地址

题目描述

给定一棵带权二叉树,请判断它是不是一个最小堆。
一棵二叉树是一个最小堆,当且仅当对于树上任意一个节点,它的权值都小于或等于以它为根的子树中的所有权值。

输入格式

输入数据第一行是一个整数T(1<=T<=100),表示测试数据的组数。
对于每组测试数据:
第一行是一个整数N(1<=N<=100),表示树的节点个数。
接下来一行包含N个正整数,第i个整数valuei(1<=valuei<=1000)表示编号i的点的权值。
接下来N-1行,每行两个整数u和v(1<=u,v<=N, u!=v),表示节点u是节点v的父节点。
测试数据保证给定的一定是一棵二叉树,并且节点1是树的根结点。

输出格式

对于每组测试数据,如果给定的树是一个最小堆则输出Yes,否则输出No。

输入样例


    3
    1
    10
    3
    10 5 3
    1 2
    1 3
    5
    1 2 3 4 5
    1 3
    1 2
    2 4
    2 5

输出样例

    Yes
    No
    Yes

AC代码

    #include<bits/stdc++.h>
    using namespace std;
    int a[110];
    int main()
    {
        int t,n,u,v;
        bool flag = true;
        cin>>t;
        while(t--){
            cin>>n;
            for(int i=1;i<=n;i++){
                cin>>a[i];
            }
            n--;
            while(n--){
                cin>>u>>v;
                if(a[u] > a[v]){
                    flag = false;
                }
            }
            if(flag){
                cout<<"Yes"<<endl;
            }else{
                cout<<"No"<<endl;
            }
            flag = true;
        }
        return 0;
    }

进程管理

题目来源

单独题解
OJ地址

题目描述

在操作系统中,进程管理是非常重要的工作,每个进程都有唯一的进程标识(PID)。每个进程都可以启动子进程,此时我们称它为其子进程的父进程,除了PID为0的进程之外,每个进程有且只有一个父进程,在这个任务中,你需要实时维护操作系统运行中的三个基本操作:

FORK PID1 PID2:标识为PID1的进程启动了一个标识为PID2的子进程。
KILL PID:结束标识为PID的进程。请注意,与此同时所有PID的子进程也将同时结束。如果PID是不存在或已经结束的进程,则不做任何操作。
QUERY PID:查询标识为PID的进程是否仍然存在。
在初始状态下,系统只开启了PID为0的进程,并且在任何情况下该进程不会结束。

输入格式

输入的第一行是一个整数T(T<=50),表示输入的数据组数。
每组测试数据的第一行是一个整数N(1<=N<=100),表示操作的数量。
每下来N行,每行按照上面的描述给出每个操作,输入保证所有的进程的PID都不相同,且一个进程结束后不会被重新启动,所有PID都是[1,100]之间的整数。

输出格式

对于每次QUERY查询,如果进程存在,输出Yes,不存在则输出No

输入样例

    2
    5
    FORK 0 1
    QUERY 1
    KILL 1
    QUERY 1
    QUERY 2
    1
    QUERY 0

输出样例

    Yes
    No
    No
    Yes

AC代码

    #include<bits/stdc++.h>
    using namespace std;
    int tree[110];
    void kill(int u){
        tree[u]=-1;
        for(int i=1;i<110;i++){
            if(tree[i]==u&&i!=u){
                kill(i);
            }
        }
    }
     
    int main()
    {
        int t,n,u,v;
        cin>>t;
        while(t--){
            cin>>n; 
            memset(tree,-1,sizeof(tree));
            tree[0] = 0;//¸ù
            while(n--){
                string s;
                cin>>s;
                if(s.find("FORK")!=string::npos){
                    cin>>u>>v;
                    tree[v]=u;
                }else if(s.find("QUERY")!=string::npos){
                    cin>>u;
                    if(tree[u]==-1){
                        cout<<"No"<<endl;
                    }else{
                        cout<<"Yes"<<endl;
                    }
                }else if(s.find("KILL")!=string::npos){
                    cin>>u;
                    kill(u);
                }
            }
        }
        return 0;
    }

网络传输

题目来源

OJ地址
单独题解

题目描述

网络的高效互联与智能传输是提升海量用户服务请求映射效率的重要措施。在这个任务中,你要用最少的传输时间,将特定的数据源发送到指定的网络节点中。
我们给定的网络一共包含N个节点(从1到N编号),其中节点1为数据源。网络中有M条无向边(u,v,w),表示一条传输线连接节点u和节点v,且数据通过这条传输线的平均时间为w。由于传送机制的限制,当一个节点接收到数据之后,它只能选择与它互连的一个节点,并将数据转发到该节点。节点1在初始化时只会发送一次数据,但在传输过程中它可以作为转发节点。
网络中有k个目标节点,你需要计算出该数据从节点1传送到所有K歌节点所需要的最短时间。注意目标节点可以按任意顺序进行传送,数据也可以多次经过同一节点。
输入格式

输入数据第一行是一个整数T(T<=5),表示测试数据的组数。
对于每组测试数据:
第一行是三个正整数N,M,K(2<=N<=1000,1<=M<=N(N-1)/2,K<=10),分别表示节点数,边数和目标节点数。
接下来M行,每行三个整数u,v,w(1<=u,v<=N, 0<=w<=1000,u!=v)。如上所述给出每条传输线。任意两个网络节点之间最多只会有一条边相连。
最后一行是K个整数,给出所有的目标节点的编号,所有目标节点的编号都在2到N之间。

输出格式

对于每组测试数据,输出数据传送到所有K个目标节点的最短时间。

样例输入


        2
        3 2 2
        1 3 1
        1 2 3
        2 3
        6 6 4
        1 5 1
        5 6 2
        2 1 20
        2 3 5
        3 4 5
        6 3 1
        2 3 4 6

样例输出


        5
        19

样例说明

在第一组样例中,最短路线是:1->3->1->2
在第二组样例中,最短路线是:1->5->6->3->2->3->4,或者1->5->6->3->4->3->2

AC代码

    #include<bits/stdc++.h>
    #define MAXN 1010
    #define INF 0x7FFFFFFF
    #define For(i,start,end) for(int i=start;i<end;i++)
    using namespace std;
    //无向图
    int Map[MAXN][MAXN];
    int main()
    {
        int t,n,m,k,u,v,w;
        scanf("%d",&t);
        while(t--){
            scanf("%d%d%d",&n,&m,&k);
            fill(Map[0],Map[0]+MAXN*MAXN,INF);
            For(i,1,n+1){
                Map[i][i]=0;
            }
            while(m--){
                scanf("%d%d%d",&u,&v,&w);
                Map[u][v]=Map[v][u]=w;
            }
            int a[k];
            For(i,0,k){
                scanf("%d",&a[i]);
            }
            //floyd
            For(tmp,1,n+1){
                For(i,1,n+1){
                    For(j,1,n+1){
                        if(Map[i][tmp]+Map[tmp][j]<Map[i][j]&&Map[i][tmp]!=INF&&Map[tmp][j]!=INF){
    //这里一定要加&&Map[i][tmp]!=INF&&Map[tmp][j]!=INF
                            Map[i][j]=Map[j][i]=Map[i][tmp]+Map[tmp][j];
                        }
                    }
                }
            }
            //全排列
            sort(a,a+k);
            int min = INF;
            int pre=1;
            do{
                int sum=0;
                pre = 1;
                for(int i=0;i<k;i++){
                    sum+=Map[pre][a[i]];
                    pre = a[i];
                }
                if(sum<=min){
                    min=sum;
                }
            }while(next_permutation(a,a+k));
            printf("%d\n",min);
        }
        return 0;
    }

哈夫曼编码(Huffman Coding)是一种编码方式,哈夫曼编码是可变字长编码(VLC)的一种。 Huffman于1952提出一种编码方法,该方法完全依据字符出现概率来构造异字头的平均长 度最短的码字,有时称之为最佳编码,一般就叫作Huffman编码。 以哈夫曼树─即最优二叉树,带权路径长度最小的二叉树,经常应用于数据压缩。 在计算信息处理中,“哈夫曼编码”是一种一致性编码法(又称"熵编码法"),用于数据的无损耗压缩。这一术语是指使用一张特殊的编码表将源字符(例如某文件中的一个符号)进行编码。这张编码表的特殊之处在于,它是根据每一个源字符出现的估算概率而建立起来的(出现概率高的字符使用较短的编码,反之出现概率低的则使用较长的编码,这便使编码之后的字符串的平均期望长度降低,从而达到无损压缩数据的目的)。这种方法是由David.A.Huffman发展起来的。 例如,在英文中,e的出现概率很高,而z的出现概率则最低。当利用哈夫曼编码对一篇英文进行压缩时,e极有可能用一个位(bit)来表示,而z则可能花去25个位(不是26)。用普通的表示方法时,每个英文字母均占用一个字节(byte),即8个位。二者相比,e使用了一般编码的1/8的长度,z则使用了3倍多。倘若我们能实现对于英文中各个字母出现概率的较准确的估算,就可以大幅度提高无损压缩的比例。 <br>
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值