http://acm.hdu.edu.cn/showproblem.php?pid=4362
题意:m个时间段,每个时间段会掉下来n个龙珠,告诉你每个时间段掉下来的所有龙珠的位置,要求每个时间段取一个龙珠(取完这个龙珠后,同一时间段的其他龙珠就消失了)
取龙珠要花费一定的能量,从一个位置走到另一个位置也要花费一定的能量,最后问你每个时间段取一个龙珠需要最少花费的能量是多少。
看了第一遍之后没看懂题- -
我们学校有人A了,继续看题,看懂了,好裸的DP,转移的时候暴力转移的话复杂度为m*n^2,肯定超时(但比赛的时候还真就这么写了。。。)
然后发现要走到某个点,要么是从左边走过来,要么是从右边走过来,所以可以直接把所有的位置预处理出来离散化一下,求第i+1层的状态时两个方向分别遍历一遍,取龙珠的能量花费再分开处理即可,具体见代码吧。
#include<cstdio>
#include<cstring>
#include<vector>
#include<set>
#include<algorithm>
using namespace std;
const int inf = ~0u>>2;
const int maxn = 50010;
const int N = 1010;
int dp[55][maxn];
int a[55][N];
int b[55][N];
vector<int> pos;
void Min(int &a,int b){
if(b==-1) return ;
if(a==-1 || b<a) a=b;
}
int g[maxn];
int main()
{
int t,m,n,x0;
scanf("%d",&t);
while(t--)
{
pos.clear();
scanf("%d%d%d",&m,&n,&x0);
pos.push_back(x0);
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
scanf("%d",&a[i][j]);
pos.push_back(a[i][j]);
}
}
sort(pos.begin(),pos.end());
int tot=unique(pos.begin(),pos.end())-pos.begin();
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
a[i][j]=lower_bound(pos.begin(),pos.begin()+tot,a[i][j])-pos.begin();
scanf("%d",&b[i][j]);
}
}
x0=lower_bound(pos.begin(),pos.begin()+tot,x0)-pos.begin();
fill(dp[0],dp[m+1],-1);
dp[0][x0]=0;
for(int i=0;i<m;i++)
{
int tmp=-1;
for(int j=0;j<tot;j++)
{
if(tmp!=-1 && j>0) tmp+=pos[j]-pos[j-1];
Min(tmp,dp[i][j]);
Min(dp[i+1][j],tmp);
}
tmp=-1;
for(int j=tot-1;j>=0;j--)
{
if(tmp!=-1 && j<tot-1) tmp+=pos[j+1]-pos[j];
Min(tmp,dp[i][j]);
Min(dp[i+1][j],tmp);
}
memset(g,-1,sizeof(g));
for(int j=0;j<n;j++)
{
int p=a[i][j];
Min(g[p],b[i][j]);
}
for(int j=0;j<tot;j++)
{
if(g[j]!=-1) dp[i+1][j]+=g[j];
else dp[i+1][j]=-1;
}
}
int ans=-1;
for(int i=0;i<tot;i++)
Min(ans,dp[m][i]);
printf("%d\n",ans);
}
return 0;
}