寒假预备役每周总结(2.2~2.4)

本文介绍了作者通过解决洛谷在线编程平台上的动态规划题目,学习动态规划的基本思想,并回顾了队列、栈和后缀表达式等相关知识。通过实例展示了如何使用动态规划解决公路修复、数楼梯和蜜蜂路线等问题。
摘要由CSDN通过智能技术生成

这几天写了前几天没写出来的题目,顺便学了一下动态规划,知道动态规划是怎样来实现的,写了几个简单的动态规划,写了一些模拟题目,看了一下有关后缀表达式的(中缀表达式转后缀表达式,后缀表达式求解)重温一下以前学的东西;

题目链接:P1111 修复公路 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

解题思路:说实话,刚开始是没想到的,后面看题解才写出来的,我都没想过要排序,题解是先把修完路的时间排个序,从最短时间来修,每修好一条路就判断一下每个村能不能互通(判断是否只有一个村的“祖宗”是自己),如果能互通就输出当前遍历到的时间;

代码实现:

#include<stdio.h>
#define N 1010
int f[N];
int n,m;
struct node
{
    int x;
    int y;
    int t;
}a[100010];
int fun(int x)
{
    if(f[x]==x)
        return x;
    else
    {
        f[x]=fun(f[x]);
        return f[x];
    }
}
void qsort(int l,int r)
{
    int mid=a[(l+r)/2].t;
    int i=l,j=r;
    while(1)
    {
        if(i>=j)
            break;
        while(a[j].t>mid)
            j--;
        while(a[i].t<mid)
            i++;
        if(i<=j)
        {
            struct node temp1=a[i];
            a[i]=a[j];
            a[j]=temp1;
            i++;
            j--;
        }
    }
    if(j>l)
        qsort(l,j);
    if(i<r)
        qsort(i,r);
}
int g()
{
    int sum=0;
    for(int j=1;j<=n;j++)
            if(f[j]==j)
                sum++;
    return sum;
}
int main()
{
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;i++)
        f[i]=i;
    for(int i=0;i<m;i++)
        scanf("%d %d %d",&a[i].x,&a[i].y,&a[i].t);
    qsort(0,m-1);
    //for(int i=0;i<m;i++)
        //printf("%d %d %d\n",a[i].x,a[i].y,a[i].t);
    for(int i=0;i<m;i++)
    {
        f[fun(a[i].y)]=fun(a[i].x);
        if(g()==1)
        {
            printf("%d",a[i].t);
            return 0;
        }
    }
    printf("-1");
    return 0;
}

题目链接:P1255 数楼梯 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

解题思路:其实把前几级台阶的走法都推导出来,就能找到规律,但是没必要那么麻烦,我们可以用dp的思想,将问题分解成子问题,通过子问题来求解总问题,我们可以想想,我要到第三级台阶是不是可以在第一台阶走两级台阶、在第二级台阶走一级台阶,这样,我们第三级台阶的走法不就等于第一级台阶和第二级台阶的走法总和,同样,我们可以推导出第四级台阶,第五级台阶,就这样,我们成功通过子问题来求解总问题,这就是dp!!!

代码实现:

#include<stdio.h>
#define N 5010
int a[N][N];
int len=1;
void fun(int x)
{
    for(int i=1;i<=len;i++)
        a[x][i]=a[x-1][i]+a[x-2][i];
    for(int i=1;i<=len;i++)
    {
        if(a[x][i]>=10)
        {
            a[x][i+1]+=a[x][i]/10;
            a[x][i]=a[x][i]%10;
            if(a[x][len+1])
                len++;
        }
    }
}
int main()
{
    int n;
    scanf("%d",&n);
    a[1][1]=1;
    a[2][1]=2;
    for(int i=3;i<=n;i++)
        fun(i);
    for(int i=len;i>=1;i--)
        printf("%d",a[n][i]);
    return 0;
}

注意:该题数据较大,要用高精度!!!(这里我wa了一次)

题目链接:P2437 蜜蜂路线 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

解题思路:一看这题就是斐波那契数列,也就是数楼梯,跟数楼梯一样的思路,这里就不介绍了

代码实现:

#include<stdio.h>
#define N 1010
int a[N][N];
int len=1;
void fun(int x)
{
    for(int i=1;i<=len;i++)
        a[x][i]=a[x-1][i]+a[x-2][i];
    for(int i=1;i<=len;i++)
        if(a[x][i]>=10)
        {
            a[x][i+1]+=a[x][i]/10;
            a[x][i]=a[x][i]%10;
            if(a[x][len+1])
                len++;
        }
}
int main()
{
    int m,n;
    scanf("%d %d",&m,&n);
    a[1][1]=1;
    a[2][1]=2;
    for(int i=3;i<=n-m;i++)
        fun(i);
    for(int i=len;i>=1;i--)
        printf("%d",a[n-m][i]);
    return 0;
}

题目链接:P1328 [NOIP2014 提高组] 生活大爆炸版石头剪刀布 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

解题思路:就纯暴力,模拟整个过程就完了,下面的代码是优化后的代码,不然要打太多的判断语句了,代码中一个二维数组便是优化,把所有结果都放到数组里面,后面直接用就行,不用打判断语句

代码实现:

#include<stdio.h>
int s[5][5]={{0,0,1,1,0},{1,0,0,1,0},{0,1,0,0,1},{0,0,1,0,1},{1,1,0,0,0}};
int main()
{
    int n,n1,n2;
    scanf("%d %d %d",&n,&n1,&n2);
    int a[n1],b[n2];
    for(int i=0;i<n1;i++)
        scanf("%d",&a[i]);
    for(int i=0;i<n2;i++)
        scanf("%d",&b[i]);
    int sum1=0,sum2=0;
    int x=0,y=0;
    while(n--)
    {
        sum1+=s[a[x]][b[y]];
        sum2+=s[b[y]][a[x]];
        if(x==n1-1)
            x=0;
        else
            x++;
        if(y==n2-1)
            y=0;
        else
            y++;
    }
    printf("%d %d",sum1,sum2);
    return 0;
}

题目链接:P1540 [NOIP2010 提高组] 机器翻译 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

解题思路:这题也是考模拟,就是涵盖了一点数据结构(队列),写完这个题也算是复习一下对列,用一个结构体来来实现队列,将第一次找的单词入队,如果队列空间不够就将最先入队的单词出队,这里还要用一个数组来标记该单词是否在队列中

代码实现:

#include<stdio.h>
#define N 1010
int a[N];
int mem[N];
struct
{
    int x;
}dl[100000];
int head=1,tail=1;
int main()
{
    int m,n;
    int res=0;
    scanf("%d %d",&m,&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for(int i=1;i<=n;i++)
    {
        if(mem[a[i]]==1)
            continue;
        else
        {
            if(tail-head==m)
            {
                mem[dl[head].x]=0;
                head++;
            }
            dl[tail++].x=a[i];
            res++;
            mem[a[i]]=1;
        }
    }
    printf("%d",res);
    return 0;
}

最后总结:本周即将结束,也是收获颇丰,学了二叉树的四种遍历方式,并查集,简单学了一下动态规划,对动态规划也是有了初步认识,复习了以前学的东西(队列,栈,dfs,bfs),还写了几个模拟题练练,下周再接再厉!!!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值