挑战程序设计竞赛书的题解总结(连载中)

写在前面的话(前言)

每天无所事事真是无趣啊,作为一个将来要征战acm的优秀青年,我感到有刷点什么的必要了!
毕竟同级的acm大佬们真是太强了,跟着老师走肯定会一直被暴打下去。。去oj上刷题呢,又感觉效率 不高,太盲目,所以毅然决然买了这本书——挑战程序设计竞赛,每天刷几道,然后不太会的再在博客上总结,感觉锤爆同级大佬,夺取acm金,走向人生巅峰的日子就在眼前了,哇嘎嘎
题目按照书的目录来,从第二章开始,书上有的题,我没有总结在这的,说明题目太简单被我秒了(没办法就是这么强)

------------------贪心篇------------------

字典序最小问题poj3617

思路是将字符串翻转并与原字符串比较

#include <bits/stdc++.h>
#include <string>
using namespace std;

string s,s1,a,s2;
int main()
{
    int n;
    cin>>n;
    int sum=0;
    for(int i=0;i<n;i++)
    {cin>>s2;s+=s2;}

    s1=s;
    while(s1.size()){
    s=s1;
    reverse(s.begin(),s.end());
    if(s<s1)
    {
        cout<<s[0];sum++;
        if(sum%80==0)cout<<endl;
        s1.erase(s1.end()-1);//这里不是删end哦
    }
    else
    {
        cout<<s1[0];sum++;
        if(sum%80==0)cout<<endl;
        s1.erase(s1.begin());
    }
    }
    return 0;
}

区间调度问题

思路:在可选的工作中,每次选取结束时间最早的工作
用到了函数upper_bound,即找数组中第一个比x大的数的下标

#include <bits/stdc++.h>

using namespace std;
int a[50],b[50];

int main()
{
    int n;
    cin>>n;
    for(int i=0;i<n;i++)cin>>a[i];//开始时间
    for(int i=0;i<n;i++)cin>>b[i];//结束时间
    int ed=b[0];
    int cnt=1;
    while(1)
    {
        int t=upper_bound(a,a+n,ed)-a;
        if(t>=n)break;
        ed=b[t];
        cnt++;
    }
    cout<<cnt<<endl;
    return 0;
}

Saruman Army(poj 3069)

这题不难,但是我用stl做,poj死活过不去,不知道卡在啥数据上了
以后回来再解决下

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int a[1005],b[50];

int main()
{
    int n,r;
    while(scanf("%d%d",&r,&n)){
    if(r==-1&&n==-1)
		break;
    for(int i=0;i<n;i++)scanf("%d",&a[i]);//开始时间
    int cnt=0;
    int x;
    sort(a,a+n);
    x=upper_bound(a,a+n,a[0]+r)-a-1;
    while(x!=n)
    {
        x=upper_bound(a,a+n,a[x]+r)-a;
        cnt++;
    }
    printf("%d\n",cnt);
    }
    return 0;
}

--------------------动态规划篇--------------

最长公共子序列问题(LCS)/2020/4/4

问题概述:给你两个序列,问你他们的最长LCS序列的长度是多少?(序列可以是不连续的,只要元素的相对位置一样)(不了解LCS问题的自行百度)

太开心了,这道题没看题解自己就做出来了,第一道完全自己推出状态转移方程的dp题,我tql,给自己orz(一眼就会做的dalao见笑了)

蒻蒟的感悟:先画一张(n+1)*(m+1)的表,更好找出规律,写出方程后也好验证

思路:dp[i][j]表示两个串前n,m个字符的最长公共序列,那么n+1 或m+1时公共序列长度也必定大于n,m的,所以继承二者最大的一个,然后当a[i]==a[j]时,公共长度+1(详见代码)

#include <bits/stdc++.h>

using namespace std;
int dp[1000][1005];//dp表示以x为尾的最长子序列的长度
string a,b;
int main()
{
    int n,m;
    cin>>n>>m;
    cin>>a>>b;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
    {
        dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
        if(a[i]==b[j])dp[i][j]++;
    }
    cout<<dp[n][m]<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zhoucheng_123/article/details/105008911