《计算机算法设计与分析》v4 第1章 算法概述 算法实现题答案

博主今年刚上大三,正好开算法这门课。由于博主本人比较喜欢算法但又比较懒,啃不动算法导论,所以决定拿这本书下手。

这本书是王晓东的第四版《计算机算法设计与分析》。初步打算将每章后面的算法题都用代码实现。

有些题跟某个ACM题目很像,我会把该ACM题的链接贴上。有的题没OJ交所以可能是错的。如有发现,还望指出。

1-1

统计数字问题

http://poj.org/problem?id=2282

这个题要按位分解,一位一位的来处理。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
int f[10];
int digit[10];
int p[10];
int dp(int cur,int num,int val,bool fst,bool lst,int number)
{
    if(cur==-1)  return 0;
    if(!fst&&!lst&&f[cur]!=-1)
        return f[cur];
    int end=lst?digit[cur]:9;
    int ans=0;
    for(int i=0; i<=end; ++i)
    {
        if(i==val)
        {
            if(i==end&&lst)
                ans+=(number%p[cur]+1)+dp(cur-1,i,val,i==0&&fst,i==end&&lst,number);
            else if(i==0&&fst)
                ans+=dp(cur-1,i,val,i==0&&fst,i==end&&lst,number);
            else ans+=p[cur]+dp(cur-1,i,val,i==0&&fst,i==end&&lst,number);
        }
        else ans+=dp(cur-1,i,val,i==0&&fst,i==end&&lst,number);
    }
    if(!fst&&!lst)
        f[cur]=ans;
    return ans;
}
void solve(int *arr,int num)
{

    int len=0;
    int var=num;
    while(num)
    {
        digit[len++]=num%10;
        num/=10;
    }
    for(int i=0; i<=9; ++i)
    {
        memset(f,-1,sizeof(f));
        arr[i]=dp(len-1,-1,i,1,1,var);
    }
}
int main()
{
    p[0]=1;
    for(int i=1; i<=9; ++i)
        p[i]=p[i-1]*10;
    int a;
    while(scanf("%d",&a)!=EOF)
    {
        int x[10];
        solve(x,a);
        for(int i=0; i<10; ++i)
            printf("%d\n",x[i]);
    }
    return 0;
}

1-2

字典序问题

这是本题的代码。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<vector>
#define LL long long
using namespace std;
int f[10][30];
int digit[10];
int dp(int pos,int num,bool fst,bool lst)
{
    if(pos==-1)
    {
        return !fst;
    }
    if(!fst&&!lst&&f[pos][num]!=-1)
        return f[pos][num];
    int beg=fst?0:num+1;
    int end=(lst?digit[pos]:26);
    int ans=0;
    for(int i=beg; i<=end; ++i)
    {
        if(i>=num)
        {
            ans+=dp(pos-1,i,i==0&&fst,i==end&&lst);
        }
    }
    if(!fst&&!lst)
        f[pos][num]=ans;
    return ans;
}
int main()
{
    char str[10];
    while(scanf("%s",str)!=EOF)
    {
        memset(f,-1,sizeof(f));
        int len=0;
        for(int i=strlen(str)-1; i>=0; --i)
            digit[len++]=str[i]-‘a‘+1;
        printf("%d\n",dp(len-1,0,1,1));
    }
    return 0;
}

由于这个题没找到原题,所以我写了一个暴力程序来检验对错。

#include<iostream>
#include<cstdio>
#include<vector>
#include<string>
using namespace std;
int a[10];
int n=6;
bool judge()
{
    for(int i=1; i<n; ++i)
        if(a[i-1]&&a[i]<=a[i-1])
            return false;
    return true;
}
int num;
void dfs(int cur )
{
    if(cur>=n)
    {
        if(judge())
        {
            cout<<num++<<":"<<endl;
            for(int i=0; i<n; ++i)
                if(a[i]==0) putchar(‘ ‘);
                else  putchar(a[i]+‘a‘-1);
            putchar(‘\n‘);
        }
        return ;
    }
    for(int i=0; i<=26; ++i)
    {
        a[cur]=i;
        dfs(cur+1);
    }
}
int main()
{
    freopen("out.txt","w",stdout);
    dfs(0);
    return 0;
}

1-3

最多约数问题

这个题由于没有数据范围,所以变成了水题。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<vector>
#define LL long long
using namespace std;
const int maxn=1000000;
int numb[maxn];
void init()
{
    for(int i=1; i<=maxn; ++i)
        for(int j=i; j<=maxn; j+=i)
            numb[j]++;
}
int main()
{
    int a,b;
    init();
    while(scanf("%d%d",&a,&b)!=EOF)
    {
        int best=0;
        for(int i=a; i<=b; ++i)
            if(numb[i]>numb[best])
                best=i;
        printf("%d\n",numb[best]);
    }
    return 0;
}

1-4

金币阵列问题

首先要认识到从初始态最终达到了最终态,它们最后的第一列一定是相同的,这第一列可能是经过某一列交换或者原来的一列,再经过相应的行翻转得来的。所以我们只需要枚举第一列是从哪一列交换而来,再通过行翻转使第一列匹配,再交换其他列,判断能否得到最终态。在各种合法情况下取最优解。

代码未验证。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<vector>
#define LL long long
using namespace std;
int n,m;
int old[101][101];
int now[101][101];
int dest[101][101];
void read(int a[][101])
{
    for(int i=1; i<=n; ++i)
        for(int j=1; j<=m; ++j)
            scanf("%d",&a[i][j]);
}
void copy(int src[][101],int dest[][101])
{
    for(int i=1; i<=n; ++i)
        for(int j=1; j<=m; ++j)
            dest[i][j]=src[i][j];
}
void flipRow(int row)
{
    for(int i=1; i<=m; ++i)
        now[row][i]^=1;
}
void swapCol(int a,int b)
{
    for(int i=1; i<=n; ++i)
        swap(now[i][a],now[i][b]);
}
bool isSame(int a,int b,int lhs[][101],int rhs[][101])
{
    for(int i=1; i<=n; ++i)
        if(lhs[i][a]!=rhs[i][b])
            return false;
    return true;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        read(old);
        read(dest);
        int ans=-1;
        for(int i=1; i<=m; ++i)
        {
            int ret=0;
            copy(old,now);
            if(!isSame(i,1,now,now))
            {
                swapCol(1,i);
                ret++;
            }
            for(int j=1; j<=n; ++j)
                if(now[j][1]!=dest[j][1])
                {
                    flipRow(j);
                    ret++;
                }
            bool ok=false;
            for(int j=2; j<=m; ++j)
            {
                ok=false;
                for(int k=j; k<=m&&!ok; ++k)
                {
                    if(isSame(k,j,now,dest))
                    {
                        if(j!=k)
                        {
                            swapCol(j,k);
                            ret++;
                        }
                        ok=true;
                        break;
                    }
                }
                if(!ok) break;
            }
            if(!ok) continue;
            if(ans==-1) ans=ret;
            else ans=min(ans,ret);
        }
        printf("%d\n",ans);
    }
    return 0;
}

1-5

最大间隙问题

这个题有点意思,用鸽巢原理做。

代码未验证。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<vector>
#define LL long long
using namespace std;
int main()
{
    double a[100];
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=1; i<=n; ++i)
            scanf("%lf",&a[i]);
        double low[100],high[100];
        int count[101];
        double mini=100000,maxi=0;
        for(int i=1; i<=n; ++i)
        {
            mini=min(a[i],mini);
            maxi=max(a[i],maxi);
        }
        for(int i=1; i<=n; ++i)
        {
            count[i]=0;
            low[i]=maxi;
            high[i]=mini;
        }
        for(int i=1; i<=n; ++i)
        {
            int buk=int(((n-1)*(a[i]-mini)/(maxi-mini)))+1;
            count[buk]++;
            if(a[i]<low[buk]) low[buk]=a[i];
            if(a[i]>high[buk]) high[buk]=a[i];
        }
        double left=high[1],tmp=0;
        for(int i=2; i<n; ++i)
            if(count[i])
            {
                tmp=max(tmp,low[i]-left);
                left=high[i];
            }
        printf("%f\n",tmp);
    }
    return 0;
}

时间: 2024-12-26 04:54:39

《计算机算法设计与分析》v4 第1章 算法概述 算法实现题答案的相关文章

【算法设计与分析】9、最小生成树,贪心算法实现

/** * 书本:<算法分析与设计> * 功能:实现用Prim算法实现寻找最小生成树 * 文件:PrimMixTree.cpp * 时间:2015年1月4日19:42:57 * 作者:cutter_point */ #include <iostream> #include <fstream> //文件输入输出流 using namespace std; const int N = 6; //这个图是一个6*6的矩阵 const int inf = 9999; ifstr

算法设计与分析基础(第3版)读书笔记(及几处翻译上的错误~~)

算法设计与分析基础(第3版) p16 in-place翻译为'在位'?'就地'更合适点 p38 amortized应翻译为'均摊','摊销'这个词简直莫名其妙(可能因为翻译是做算法交易导致的?) p64 迭代优于递归(迭代始终是增量式的,而递归就没办法增量了,除非能够dump整个运行时栈) p73 通过算法可视化得到一个更好的非递归算法(人的图像认知直觉思维?) p79 验证一个拓扑是环.星.还是团?(这个地方有点意思,因为我想到了动态的Verify) p87 凸包问题:从数据结构上讲,Set<

算法设计与分析(屈婉玲)pdf

下载地址:网盘下载 算法设计与分析本教材为计算机科学技术专业核心课程"算法设计与分析"教材.<算法设计与分析>以算法设计技术和分析方法为主线来组织各知识单元,主要内容包括基础知识.分治策略.动态规划.贪心法.回溯与分支限界.算法分析与问题的计算复杂度.NP完全性.近似算法.随机算法.处理难解问题的策略等.书中突出对问题本身的分析和求解方法的阐述,从问题建模.算法设计与分析.改进措施等方面给出适当的建议,同时也简要介绍了计算复杂性理论的核心内容和处理难解问题的一些新技术. &

(转)常用的算法设计与分析-一夜星辰的博客

算法设计与分析 分治法 思想 1. 将一个规模为n的问题分解为k个规模较小的子问题,这些子问题互相独立且与原问题相同.递归地解这些子问题,然后将各子问题的解合并得到原问题的解. 2. divide-and-conquer(P) { if(|P| <= n0)adhoc(P); divide P into samller subinstances P1,P2...,Pk; for(int i = 1;i < k;i++) { yi = divide-and-conquer(Pi); } retu

算法设计与分析 ------最近对问题与8枚硬币问题

利用减治法实现8枚硬币问题: 参考资料:http://blog.csdn.net/wwj_748/article/details/8863503    算法设计--八枚硬币问题 1 #include "stdafx.h" 2 #include <iostream> 3 #include <stdio.h> 4 using namespace std; 5 6 7 void eightcoin(int arr[]); 8 void compare(int a,in

【通知】《算法设计与分析》实验课、理论课补课、考试时间、加分等安排 及 个人目标设定

Logistic回归为概率型非线性回归模型,是研究二分类观察结果与一些影响因素之间关系的一种多 变量分析方法.通常的问题是,研究某些因素条件下某个结果是否发生,比如医学中根据病人的一些症状来判断它是 否患有某种病. 在讲解Logistic回归理论之前,我们先从LR分类器说起.LR分类器,即Logistic Regression Classifier. 在分类情形下,经过学习后的LR分类器是一组权值,当测试样本的数据输入时,这组权值与测试数据按 照线性加和得到 这里是每个样本的个特征. 之后按照s

算法设计与分析——回溯法算法模板

以深度优先方式系统搜索问题解的算法称为回溯法.在回溯法中,解空间树主要分为了四种子集树.排列树.n叉树和不确定树. 在<算法设计与分析课本>中介绍了11个回溯法的问题样例,这里根据解空间树的类型做一个分类. 子集树 装载问题 符号三角形问题 0-1背包问题 最大团问题 算法模板: void backtrack(int t) { if(搜索到叶子结点) { return; } for(i=0; i<=1; i++) //01二叉树 { if(满足约束函数和限界函数)//剪枝 { backt

算法设计与分析-Week12

题目描述 You are given coins of different denominations and a total amount of money amount. Write a function to compute the fewest number of coins that you need to make up that amount. If that amount of money cannot be made up by any combination of the c

算法设计与分析课程复习笔记(1)

一.计算模型 1.1 定义: 我们在思考和处理算法的时候是机器无关.实现语言无关的.所有的算法运行在一种"抽象的机器"之上,这就是计算模型. 1.2 种类 图灵机是最有名的计算模型,本课使用更简单更合适的RAM计算模型. 1.3 RAM(Random Access Machine)模型 RAM模型的基本构成如下: RAM计算模型有如下特点: 一个简单操作花费一步:键值比较.加减.内存访问 没有操作可以被分解:循环.子程序 内存:访存是一个简单操作.无限制的内存 二.算法设计 2.1 算