算法分析与设计习题解

算法题解答

算法分析与设计 题目解答。题目在http://47.99.179.148

分治

test_6

#include <iostream>
using namespace std;

//堆排序用数组存的方式
void minHeapSort(int a[], int current, int high){
    //current是当下需要调整的节点,high为数组边界
    int i = current;
    int j = i*2;
    while(j <= high){
        if(a[j+1] < a[j] && j+1 <= high){//先是同层级比较
            j = j + 1;
        }

        if(a[j] < a[i]){//若儿子比父节点小,则交换
            swap(a[i],a[j]);
            i = j;
            j = 2*i;
        } else{//否则跳出循环,不动
            break;
        }
    }
}

int main() {
    int n;
    cin >> n;

    int q[n][1000];
    unsigned char c;

    //输入
    c = getchar();
    for(int i=0; i<n; i++){
        int j = 0;
        while((c=getchar()) != '\n'){
            if(c != ' '){
                ungetc(c,stdin);//如果c不是空格要把c还回到流中
                cin >> q[i][j++];
            }
        }
    }

    //应用堆排序
    for (int i = 0; i < n; ++i) {
        for (int j = q[i][0]/2; j >= 1 ; j--) {//自下向上,自右向左调整顺序
            minHeapSort(q[i],j,q[i][0]);
        }
    }

    //输出
    for(int i=0; i<n; i++){
        for(int j=1; j<=q[i][0]; j++){
            cout << q[i][j] << " ";
        }
        cout << endl;
    }

    return 0;
}

test_11,最近点对

#include <iostream>
#include <algorithm>
#include <cmath>

using namespace std;

int M,N;

struct Point{
    int x;
    int y;
};
Point p[50001];

//输入函数
void input(){
    scanf("%d",&N);
    for(int i = 0; i < N; i++){
        Point point{};
        scanf("%d %d",&point.x,&point.y);
        p[i] = point;
    }
}

//对点排序,先按照横坐标排序,横坐标相同就按照纵坐标排序
bool cmp(const Point& p1,const Point& p2){
    return p1.x == p2.x ? p1.y < p2.y : p1.x < p2.x;
}

//内联函数获取两点间距
inline double dis(const Point& p1, const Point& p2){
    return sqrt((p1.x-p2.x)*(p1.x-p2.x) + (p1.y-p2.y)*(p1.y-p2.y));
}

//求解最近点对
double divide(int left, int right, Point* pPoint){
    Point point[50001];
    if(left == right) return 0;
    //分治
    int mid = (left+right)/2;
    Point p1{};
    p1 = pPoint[mid];
    //求解左边点集合和右边点集的最小距离,并再取最小
    double d = min(divide(1, mid, pPoint), divide(mid + 1, right, pPoint));

    int i = 1, j = mid+1, k = 0;
    //将左右两边的点根据横坐标再纵坐标排序合并入临时点数组中
    while (i <= mid && j <= right){
        if(pPoint[i].y < pPoint[j].y) point[k++] = pPoint[i++];
        else point[k++] = pPoint[j++];
    }
    while (i <= mid){
        point[k++] = pPoint[i++];
    }
    while (j <= right){
        point[k++] = pPoint[j++];
    }

    //讨论一点在左半边一点在右半边的情况
    k = 0;
    for(i = 1; i<=right; i++){
        if(fabs(p1.x-point[i-1].x)<d) point[k++] = point[i-1];
    }
    for(i=0;i<k;i++){
        for(j=i+1; point[j].y-point[i].y<d && j<k; j++){
            d = min(d,dis(point[i],point[j]));
        }
    }
    return d;
}




int main() {
    cin >> M;

    for(int i = 0 ; i < M; i++){
        //输入
        input();
        //排序
        sort(p,p+N,cmp);
        //数组最小距离
        double d = divide(0,N-1,p);
        printf("%.2lf\n",d);
    }
    //for_each(points.begin(),points.end(), showMinDistance);//first和last都是迭代器对象,至于第三个参数会自己取内容传入
    /*
    for(vector<Point>::iterator i = points.begin();i != points.end();i++){//迭代器本质上是指向向量中对象的指针
        cout << i->x << i->y << endl;
    }
     */

    return 0;
}

test_13

#include <iostream>
using namespace std;

int N;
long long Count = 0;
int a[50001],b[50001];

void input(){
    scanf("%d", &N);
    for(int i=0;i<N;i++){
        scanf("%d", &a[i]);
    }
}

//用归并排序(分治)
void solve(int left, int right){
    if(left >= right) return;

    int mid = (left + right)/2;
    solve(left,mid);
    solve(mid+1,right);

    int i=left, j=mid+1, k=0;
    while (i<=mid && j<=right){
        if(a[i] > a[j]) {
            b[k++] = a[j++];
            Count += mid-i+1;
        } else{
            b[k++] = a[i++];
        }
    }
    while (i <= mid){
        b[k++] = a[i++];
    }
    while (j<= right){
        b[k++] = a[j++];
    }
    for(int i=left,j=0; i<=right; i++,j++){
        a[i] = b[j];
    }
}

int main() {
    int M;
    cin >> M;

    for(int i=0; i<M; i++){
        input();

        solve(0,N-1);

        cout << Count << endl;
        Count = 0;
    }

    return 0;
}

test_13,归并排序

#include <iostream>
using namespace std;

int N;
long long Count = 0;
int a[50001],b[50001];

void input(){
    scanf("%d", &N);
    for(int i=0;i<N;i++){
        scanf("%d", &a[i]);
    }
}

//用归并排序(分治)
void solve(int left, int right){
    if(left >= right) return;

    int mid = (left + right)/2;
    solve(left,mid);
    solve(mid+1,right);

    int i=left, j=mid+1, k=0;
    while (i<=mid && j<=right){
        if(a[i] > a[j]) {
            b[k++] = a[j++];
            Count += mid-i+1;
        } else{
            b[k++] = a[i++];
        }
    }
    while (i <= mid){
        b[k++] = a[i++];
    }
    while (j<= right){
        b[k++] = a[j++];
    }
    for(int i=left,j=0; i<=right; i++,j++){
        a[i] = b[j];
    }
}

int main() {
    int M;
    cin >> M;

    for(int i=0; i<M; i++){
        input();

        solve(0,N-1);

        cout << Count << endl;
        Count = 0;
    }

    return 0;
}

test_16

#include <iostream>
#include <algorithm>
using namespace std;

int N,X;
int a[50001];

void input(){
    scanf("%d %d",&N,&X);
    for(int i=0; i<N; i++){
        scanf("%d",&a[i]);
    }
}

bool binary_search(int x, int low, int high){
    if(low > high){//出口设置要谨慎
        return false;
    }

    int mid = (low + high)/2;

    if(a[mid] == x){
        return true;
    } else if(a[mid] < x){
        binary_search(x,mid+1,high);
    } else {
        binary_search(x,low,mid-1);
    }
}

void solve(){
    int m,count = 0;
    for(int i=0; i<N; i++){
        m = X - a[i];
        if(binary_search(m,0,N-1)){
            count++;
        }
    }

    if(count !=0){
        cout << "yes" << endl;
    } else{
        cout << "no" << endl;
    }
}

int main() {
    int M;
    cin >> M;

    for(int i=0; i<M; i++){
        input();

        sort(a,a+N);

        solve();
    }
    return 0;
}

动态规划

test_7

#include <iostream>
#include <string>
#include <cstring>

using namespace std;
int main() {
    int n;//记录组数
    cin >> n;

    int Input[3];
    int Answer[n];
    char str[41];

    int dp[41][7];//用矩阵存放乘积中间结果
    int num[41][41];

    //格式输入
    unsigned char c;
    c = getchar();
    for (int t = 0; t < n; ++t) {
        int j = 0;
        //分割字符,控制输入
        while ((c=getchar())!='\n'){
            if(c != ' '){
                ungetc(c,stdin);
                cin >> Input[j++];
            }
        }
        //开始处理
        //数字入num
        for(int i=0;i<Input[0];i++){
            itoa(Input[2],str,10);
            int temp = 0;
            for(int j=i;j<Input[0];j++){
                temp = temp*10 + str[j] - '0';
                num[i][j] = temp;
            }
        }
        //用0初始化
        memset(dp, 0, sizeof(dp));
        memset(num, 0, sizeof(num));
        //当不插入乘号后,最大乘积为本身
        for (int i = 0; i < Input[0]; ++i) {
            dp[i][0] = num[0][i];
        }
        //动态转移方程,更新解
        for (int i = 0; i < Input[0]; ++i) {
            for (int k = 1; k <= Input[1]; ++k) {
                for (int l = 0; l < i; ++l) {
                    dp[i][k] = max(dp[l][k-1]*num[l+1][i],dp[i][j]);
                }
            }
        }

        Answer[t] = dp[Input[0]-1][Input[1]];
    }

    for (int i = 0; i < n; ++i) {
        cout << Answer[i] << endl;
    }

    return 0;
}

test_14

#include <iostream>
using namespace std;

int N;
int maxSum = 0;
int a[50001];

void input(){
    scanf("%d", &N);
    for(int i=0;i<N;i++){
        scanf("%d", &a[i]);
    }
}

void solve(){
    int dp[N];
    //初始化
    dp[0] = a[0];
    maxSum = a[0];

    for(int i=1; i<N; i++){
        if(dp[i-1] < 0){
            dp[i] = a[i];//如果之前的加和结果已然为-,评价为应该从头开始
        } else{
            dp[i] = dp[i-1] + a[i];
            maxSum = max(dp[i],maxSum);
        }
    }
}

int main() {
    int M;
    cin >> M;

    for(int i=0; i<M; i++){
        input();

        solve();

        cout << maxSum << endl;
        maxSum = 0;
    }

    return 0;
}

背包问题

test_18,背包

#include <iostream>
using namespace std;
int INT_MIN = -100;

int main(){
 int m,n,C;

 cin>>m;
 while(m--){
  cin>> n >> C;//n是宝石数目,c是背包容量
  int w[n+1],v[n+1],dp[C+1];//w是重量,v是价值

  dp[0]=0;
  for(int i=1;i<=C;i++)
      dp[i]=INT_MIN;

  for(int i=1;i<=n;i++){
      cin>>w[i]>>v[i];
  }

  //动态规划问题
  for(int i=1; i<=n; i++)
      for(int j=C; j>=w[i]; j--)
          dp[j]=max(dp[j],dp[j-w[i]]+v[i]);

  if(dp[C]<0)
      dp[C]=0;

  cout << dp[C] << endl;
 }
 return 0;
}

特别的

test_24

#include <iostream>
#include <iomanip>
using namespace std;
#define INF 0X3f3f3f3f

int key[500];
double p[501], q[501], c[501][501], w[501][501];


void BST(double p[], double q[], int n){
    for(int i=0; i<=n; i++){
        c[i][i] = 0;//c(i,j)表示第i+1到j个key构造的最优二叉树的代价(平均搜索长度asl,找到和没找到要加起来),则c(0,n)是最后结果
        w[i][i] = q[i];//w(i,j)表示第i+1到j个key权值及第i到j个空隙权值(空隙权值就是关键字外的搜索概率)和
    }

    for(int x=1; x<=n; x++){
        for(int i=0; i<=n-x; i++){
            int j = i + x;//不断以i到j为内容建树(迭代)
            c[i][j] = INF;
            w[i][j] = w[i][j-1] + p[j] + q[j];
            for(int k=i+1; k<=j; k++){//以k为根的最优二叉树代价
                c[i][j] = min(c[i][j],w[i][j]+c[k][j]+c[i][k-1]);
            }
        }
    }
}

int main() {
    int M, N;
    cin >> M;

    for(int i=0; i<M; i++){
        cin >> N;
        for(int j = 0; j<N; j++) cin >> key[j];//N个从小到大排好的数
        for(int j = 1; j<=N; j++) cin >> p[j];//N个关键字搜索概率
        for(int j = 0; j<=N; j++) cin >> q[j];//搜索关键字外的概率

        BST(p,q,N);
        //最终结果是从c[0][N],前面c[i][j]是不断建树记录的过程
        cout << fixed<<setprecision(6)<< c[0][N] << endl;
    }

    return 0;
}

test_25

#include <cstdio>
#include <algorithm>
#include <iostream>
using namespace std;

int A[10001], dp[10001], N;	// 序列和, dp数组, 数字总数

void input(){
    scanf("%d", &N);
    for(int i=0; i<N; i++){
        scanf("%d", &A[i]);
    }
}

void solve(){
    int ans = -1;	// 记录最大的 dp[i]
    for(int i = 0; i < N; i++) {
        dp[i] = 1;	// 至少能够自身成为一条 LIS
        for(int j = 0; j < i; j++){	// 只需要递归到小于 i
            // 如果不比之前的小,而且新形成的子序列更大,则接到这个人后面来
            if(A[i] >= A[j] && (dp[j] + 1 > dp[i])) {
                dp[i] = dp[j] + 1;
            }
        }
        ans = max(ans, dp[i]);	// 确定当前结束的最长子序列的长度之后,比较
    }
    printf("%d", ans);
}

int main() {
    int M;
    cin >> M;

    for(int i=0; i<M; i++){
        input();
        solve();
    }


  return 0;
}
test_25自己解答
#include <iostream>
#include <stack>
#include <algorithm>
using namespace std;

int N;
int a[10001], ct[10001];
stack<int> a_stack;

void input(){
    scanf("%d", &N);
    for(int i=0; i<N; i++){
        scanf("%d", &a[i]);
    }
}

int clear_stack(){
    int c = 0;
    while (!a_stack.empty()){
        a_stack.pop();
        c++;
    }
    return c;
}

void solve(){
    for(int i=0; i<N; i++){
        a_stack.push(a[i]);
        int s_stack_t = a[i];

        for(int j=i+1; j<N; j++){
            if(a[j] >= a_stack.top()){
                s_stack_t = a_stack.top();
                a_stack.push(a[j]);
            }
            if(a[j] < a_stack.top() && a[j] >= s_stack_t){//为求最长子序列,入栈的元素曲线要尽可能平滑
                a_stack.pop();
                s_stack_t = a_stack.top();
                a_stack.push(a[j]);
            }
        }
        ct[i] = clear_stack();
    }
}

void output(){
    sort(ct,ct+N);
    cout << ct[N-1] << endl;
}

int main() {
    int M;
    cin >> M;

    for(int i=0; i<M; i++){
        input();
        solve();
        output();
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值