2012 Multi-University Training Contest 7-1003 hdu4362 Dragon Ball

本文解决了一个寻找最优路径来收集所有龙珠的问题,采用动态规划算法并利用单调队列进行优化,详细介绍了输入输出格式及核心代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意: Sean有一张藏宝图,藏宝图会告诉他在接下来的m个时期内会出现n个龙珠(在不同的位置),从位置x移动到位置y需要话费|x-y|的能量,拿龙珠也需要一定的能量,每个时期他能切只能拿一个龙珠,问他拿完所有的龙珠需要的最小的能量是多少。


输入:m,n,x  代表有m个时期,每个时期都出现n个龙珠,以及Sean的初始位置x

然后两个m*n的矩阵,第一个矩阵表示在第i个时期第j个龙珠的位置,第二个矩阵代表第i个时期第j个龙珠需要花费的能量。


要求输出最小需要花费的能量。


解法:DP(单调队列优化用堆优化也可以过……)


#include <iostream>
#include <memory.h>
#include <cstdio>
#include <iterator>
#include <algorithm>
#include <cmath>
#include <map>

using namespace std;

long long m=1<<30;
long long MAX = m*m;
multimap<long long,int> add;
multimap<long long,int> red;
pair<long long,int> tmpPair;
multimap<long long,int>::iterator it;
long long dp[55][1002];

int ab(int num)
{
    if(num>=0) return num;
    else return -num;
}

struct Node
{
    int loc;
    int ener;
    bool operator<(const Node& nd)const
    {
        if(loc<nd.loc) return true;
        else return false;
    }
}ene[55][1002];

int main()
{
    int k,n,m,x,curr;
    long long minVal;
    while(scanf("%d",&k)!=EOF)
    {
        while(k--)
        {
            scanf("%d%d%d",&n,&m,&x);
            for(int i=0;i<n;i++)
            {
                for(int j=0;j<m;j++) scanf("%d",&(ene[i][j].loc));
            }
            for(int i=0;i<n;i++)
            {
                for(int j=0;j<m;j++) scanf("%d",&(ene[i][j].ener));
            }
            add.clear();
            red.clear();
            for(int i=0;i<n;i++)
            {
                sort(ene[i],ene[i]+m);
            }
            for(int j=0;j<m;j++)
            {
                dp[0][j] = ene[0][j].ener+ab(ene[0][j].loc-x);
                add.insert(pair<long long,int>(dp[0][j]+ene[0][j].loc,ene[0][j].loc));
                red.insert(pair<long long,int>(dp[0][j]-ene[0][j].loc,ene[0][j].loc));
            }
            for(int i=1;i<n;i++)
            {
                for(int j=0;j<m;j++) dp[i][j]=MAX;
                curr=0;
                while(!add.empty())
                {
                    it=add.begin();
                    tmpPair=*it;
                    for(curr;curr<m&&ene[i][curr].loc<=tmpPair.second;curr++)
                    {
                        dp[i][curr]=min(dp[i][curr],tmpPair.first+ene[i][curr].ener-ene[i][curr].loc);
                    }
                    add.erase(it);
                }
                curr=m-1;
                while(!red.empty())
                {
                    it=red.begin();
                    tmpPair=*it;
                    for(curr;curr>=0&&ene[i][curr].loc>=tmpPair.second;curr--)
                    {
                        dp[i][curr]=min(dp[i][curr],tmpPair.first+ene[i][curr].ener+ene[i][curr].loc);
                    }
                    red.erase(it);
                }
                for(int j=0;j<m;j++)
                {
                    add.insert(pair<long long,int>(dp[i][j]+ene[i][j].loc,ene[i][j].loc));
                    red.insert(pair<long long,int>(dp[i][j]-ene[i][j].loc,ene[i][j].loc));
                }
            }
            minVal = MAX;
            for(int j=0;j<m;j++)
            {
                if(dp[n-1][j]<minVal) minVal=dp[n-1][j];
            }
            printf("%I64d\n",minVal);
        }
    }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值