【C++心路历程24】龙珠【dp加单调队列】

    xiaoxiao2021-03-25  87

    【问题描述】

      你得到了一个龙珠雷达,它会告诉你龙珠出现的时间和地点。

      龙珠雷达的画面是一条水平的数轴,每一个窗口时间,数轴的某些点上会出现同一种龙珠,每当你获得其中一颗龙珠,其它龙珠就会消失。下一个窗口时间,数轴上又会出现另一种龙珠。总共有n个窗口时间,也就是总共有n种龙珠。

      假设你会瞬间移动,你从数轴的x点移动到y点,耗时0秒,但是需要耗费|x-y|的体力。同时,挖出一颗龙珠也需要耗费一定的体力。请问,最少耗费多少体力,就可以收集齐所有种类的龙珠。

    【输入格式】

      第一行,三个整数n,m,x,表示共有n个窗口时间,每个窗口时间会出现m个龙珠,x是一开始你所处的位置。   接下来有两个n*m的矩阵。   对于第一个矩阵,坐标为(i,j)的数字表示第i个窗口时间,第j个龙珠的位置。   对于第二个矩阵,坐标为(i,j)的数字表示第i个窗口时间,挖取第j个龙珠所需的体力。

    【输出格式】

      一个整数,表示所需最小体力

    【输入样例】

    3 2 5 2 3 4 1 1 3 1 1 1 3 4 2

    【输出样例】

    8

    【数据范围】

    所有数据均为整数 数轴范围在0到30000 挖一颗龙珠所需体力不超过30000 结果保证在int范围 对于50%的数据,1<=n<=50,1<=m<=500。 对于100%的数据,1<=n<=50,1<=m<=5000。

    不难分析出动态规划方程: 设结构体:a[i][j].x=表示第 i 个时间窗口出现的第 j 个龙珠的位置。 :a[i][j].c=表示第 i 个时间窗口挖第 j 个龙珠需要耗费的体力。 //f(i,j)表示在第i个窗口拾取第j个龙珠后所耗费的最小体力 //f(i,j)=min(f(i-1,k)+abs(a[i-1][k].wz-a[i][j].wz) || 1<=k<=m )+a[i][j].c 边界: f(1,j)= |a[1][j].x-x0|+ a[1][j].c //在第 1 个时间窗口收集第 j 个龙珠需要的体力

    纯粹dp:

    solve50() for(int j=1;j<=m;j++) f[1][j]=abs(a[1][j].wz-p)+a[1][j].c; //f(i,j)表示在第i个窗口拾取第j个龙珠后所耗费的最小体力 //f(i,j)=min( f(i-1,k)+abs(p[i-1][k].wz-p[i][j].wz) || 1<=k<=m )+p[i][j].c for(int i=2;i<=n;i++) { for(int j=1;j<=m;j++) { ans=inf; for(int k=1;k<=m;k++) { rr=f[i-1][k]+abs(a[i-1][k].wz-a[i][j].wz); ans=min(ans,rr); } f[i][j]=ans+a[i][j].c; } } ans=inf; for(int i=1;i<=m;i++) ans=min(ans,f[n][i]); printf("%d",ans);

    加入单调队列优化(偷个懒,因为这个滑动窗口左端固定,不用记录下标,只找最小值):

    solve100() for(int i=2;i<=n;i++) { int k=1; int minv=inf; //when(p[i][j].wz>=p[i-1][k].wz) //f(i,j)=min(f(i-1,k)-p[i-1][k].wz) || 1<=k<=m )+p[i][j].c+p[i][j].wz for(int j=1;j<=m;j++) { while(k<=m && a[i][j].wz>=a[i-1][k].wz) { t=f[i-1][k]-a[i-1][k].wz; minv=min(minv,t); k++; } f[i][j]=minv+a[i][j].c+a[i][j].wz; } k=m,minv=inf; //when(p[i][j].wz<p[i-1][k].wz) //f(i,j)=min(f(i-1,k)+p[i-1][k].wz) || 1<=k<=m )+p[i][j].c-p[i][j].wz for(int j=m;j>=1;j--) { while(k>=1 && a[i][j].wz<a[i-1][k].wz) { t=f[i-1][k]+a[i-1][k].wz; minv=min(minv,t); k--; } f[i][j]=min(f[i][j],minv+a[i][j].c-a[i][j].wz); } } ans=inf; for(int i=1;i<=m;i++) ans=min(ans,f[n][i]); printf("%d",ans);
    转载请注明原文地址: https://ju.6miu.com/read-5523.html

    最新回复(0)