题意: 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);
}
}
}