算法设计与分析exp(4)减治技术

1、确定比赛名次(拓扑排序)

【问题描述】
有N个比赛队(1<=N<=500),编号依次为1,2,3,。。。。,N进行比赛,比赛结束后,裁判委员会要将所有参赛队伍从前往后依次排名,但现在裁判委员会不能直接获得每个队的比赛成绩,只知道每场比赛的结果,即P1赢P2,用P1,P2表示,排名时P1在P2之前。现在请你编程序确定排名。

【输入形式】
输入有若干组,每组中的第一行为二个数N(1<=N<=500),M;其中N表示队伍的个数,M表示接着有M行的输入数据。接下来的M行数据中,每行也有两个整数P1,P2表示即P1队赢了P2队。

【输出形式】
给出一个符合要求的排名。输出时队伍号之间有空格,最后一名后面没有空格。

其他说明:符合条件的排名可能不是唯一的,此时要求输出时编号小的队伍在前;输入数据保证是正确的,即输入数据确保一定能有一个符合要求的排名。

【样例输入】
4 3 1 2 2 3 4 3

【样例输出】
1 2 4 3

【参考代码】

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const int maxn = 1000;
int g[maxn][maxn],indgr[maxn],res[maxn];

void topsort(int n){
    int k = 0;
    for(int i = 1;i <= n;i++){
        for (int j = 1; j <= n; j++) {
            if(!indgr[j]){
                res[i] = j;
                indgr[j] --;
                k = j;
                break;
            }
        }
        for (int j = 1; j <= n; j ++) {
            if(g[k][j] == 1){
                g[k][j] = 0;
                indgr[j] --;
            }
        }
    }
}

void myoutput(int n){
    for (int i = 1; i <=n; i ++) {
        if(i<n)
            printf("%d ",res[i]);
        else
            printf("%d\n",res[i]);
    }
}
int main(int argc, const char * argv[]) {
    int n , m;
    while (~scanf("%d%d",&n,&m)) {
        int x,y;
        memset(indgr,0,sizeof(indgr));
        memset(g,0,sizeof(g));
        for(int i = 1;i <= m;i ++){
            scanf("%d%d",&x,&y);
            if(!g[x][y])
                g[x][y] = 1;
            indgr[y]++;
        }
        topsort(n);
        myoutput(n);
    }
    return 0;
}



2、确定比赛名次(深搜拓扑排序)

【问题描述】
有N个比赛队(1<=N<=500),编号依次为1,2,3,。。。。,N进行比赛,比赛结束后,裁判委员会要将所有参赛队伍从前往后依次排名,但现在裁判委员会不能直接获得每个队的比赛成绩,只知道每场比赛的结果,即P1赢P2,用P1,P2表示,排名时P1在P2之前。现在请你编程序确定排名。

【输入形式】
输入有若干组,每组中的第一行为二个数N(1<=N<=500),M;其中N表示队伍的个数,M表示接着有M行的输入数据。接下来的M行数据中,每行也有两个整数P1,P2表示即P1队赢了P2队。

【输出形式】
给出一个符合要求的排名。输出时队伍号之间有空格,最后一名后面没有空格。

其他说明:符合条件的排名可能不是唯一的,此时要求输出时编号小的队伍在前;输入数据保证是正确的,即输入数据确保一定能有一个符合要求的排名。

【样例输入】
4 3 1 2 2 3 4 3

【样例输出】
4 1 2 3

提示:本题目要求用DFS算法求解拓扑排序。基本思想是:执行一次DFS遍历,并记住顶点变成死端(即退出遍历栈)的顺序。将该次序反过来就得到拓扑排序的一个解。要求把这个解输出。

#include<bits/stdc++.h>
using namespace std;
int num[500];
bool vis[500];
vector<int>a[500],res;

void dfs(int i) {
    for (int x:a[i]) {
        if (vis[x]) {
            continue;
        }
        vis[x]=1;
        dfs(x);
    }
    res.push_back (i);
}

int main(){
    int n, m;
    while(cin>>n>>m) {
        res.clear();
        for(int i=1;i<=n;i++) {
            a[i].clear();
            num[i]=0;
            vis[i]=0;
        }
        while(m--) {
            int l,r;
            cin>>l>>r;
            a[l].push_back(r);
            num[r]++;
        }
       
        for(int i=1;i<=n;i++){
            if (!vis[i]) {
                dfs(i);
                vis[i]=1;
            }
        }
        int len =res .size();
        for(int i=len-1;i>=0;i--) {
            cout<<res[i]<<" ";
        }
        cout<<endl;
    }
    return 0;
}

3、插入排序

【问题描述】

lzz今天学会了插入排序,他觉得插入排序很有趣。现在他有一个长为n的序列,而且这个序列中没有相同的数。现在他想对这个数列进行m次操作。每次操作他会选择一个序列中的元素x,然后他可以选择将x从序列中拿出来放到序列的尾部;或者将x取出来,然后把序列按顺序输出,再将x插入到原来的位置。但是他做了很久也没做出来,于是他请你来完成这个任务。

【输入形式】

第一行输入一个整数n。
第二行按顺序输入n个整数,表示lzz的序列。
第三行输入一个整数m。
后面m行,每行两个整数a,b,若a=0,表示lzz将b取出来并放到序列的尾部;若a=1,表示lzz要将b取出来后输出,然后再将b放回原位。
(1<=n,m<=5000)

【输出形式】

对于每一个a=1,输出一行。
每行n-1个整数,表示lzz取出了b之后的序列。

【样例输入】

10
1 2 3 4 5 6 7 8 9 10
5
0 5
1 10
1 7
0 9
1 8

【样例输出】

1 2 3 4 6 7 8 9 5
1 2 3 4 6 8 9 10 5
1 2 3 4 6 7 10 5 9

【样例说明】

1<=n,m<=5000

【参考代码】

#include <iostream>

void myoutput(int a[],int q){
    for(int i = 0;i<q;i++)
    {
        printf("%d ",a[i]);
    }
    printf("\n");
}
int main(int argc, const char * argv[]) {
    int n;
    scanf("%d",&n);
    int lzz[10000];
    for(int i=0;i<n;i++){
        scanf("%d",&lzz[i]);
    }
    int m,a,b;
    scanf("%d",&m);
    for(int j=1;j<=m;j++)
    {
        scanf("%d%d",&a,&b);
        if(a == 0)
        {
            for(int k = 0;k<n;k++)
                if(b==lzz[k])
                {
                    for(int p = k;p<n;p++)
                        lzz[p]=lzz[p+1];
                    lzz[n-1]=b;
                }
        }
        else
        {
            int k;
            for(k = 0;k<n;k++)
            {
                if(b==lzz[k])
                {
                    for(int p = k;p<n;p++)
                        lzz[p]=lzz[p+1];
                    break;
                }
            }
            myoutput(lzz,n-1);
            for(int c = n-1;c>k;c--)
                lzz[c]=lzz[c-1];
            lzz[k]=b;
        }
    }
    
}

 4、减一技术实现求a的n次幂

【问题描述】给定两个正整数a和n,求a的n次幂;其中a<100,b<20;
【输入形式】两个整数a,n(a与n中间用空格隔开);
【输出形式】一个整数
【样例输入1】2 3
【样例输出1】8

【样例输入1】3 4
【样例输出1】81

【参考代码】

#include <stdio.h>
#include <stdlib.h>
int power(int a,int n)
{
    int res = a;
       for(int i=n;i>1;i--)
           res = res*a;
       return res;
}
int main()
{
   int a,n;
  scanf("%d%d",&a,&n);
   printf("%d",power(a,n));
    return 0;
}

5、减半技术实现求a的n次幂

【问题描述】给定两个正整数a和n,采用减半技术求a的n次幂;其中a<100,b<20;
【输入形式】两个整数a,n(a与n中间用空格隔开);
【输出形式】一个整数
【样例输入1】2 3
【样例输出1】8

【样例输入1】3 4
【样例输出1】81

【参考代码】

#include <stdio.h>
#include <stdlib.h>
int power(int a,int n)
{
    int temp;
    if(n==1)return a;
    else
    {
        if(n%2==0)
        {
            //return  pow(power(a,n/2), 2);
            return power(a*a,n/2);
        }
        else
        {
           //return pow(power(a,(n-1)/2), 2)*a;
           return power(a*a,(n-1)/2)*a;
        }
    }

}
int main()
{

   int a,n;
  scanf("%d%d",&a,&n);
   printf("%d",power(a,n));
    return 0;
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值