hdu 4362 Dragon Ball 很裸的DP

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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值