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