hdu4362(Dragon Ball)(动态规划)

 

http://acm.hdu.edu.cn/showproblem.php?pid=4362

(1)动态规划 d[i][j]=min(d[i-1][k] + |a[i-1][k].x - a[i][j].x| + a[i][j].p);

(2)去绝对值技巧:对上一层数轴上的 x 值排序,上面每个元素xL[j]=min(xL[j-1] , d[i-1][j]-a[i-1][j].x) ,xR[j]=min(xR[j+1] , d[i-1][j]+a[i-1][j].x) 。

(3)对于每个d[i][j] 只要通过a[i][j].x判断在上一层什么位置就行了,对于有序的序列查找位置。

动态规划+排序预处+二分

他人具体代码:

View Code
 #include<iostream>
 #include<algorithm>
 #include<cstring>
 #include<cstdio>
 #include<cmath>
 #define MAXM 55
 #define MAXN 1010
 
 using namespace std;
 
 struct point
 {
     int x,p;
 }a[MAXM][MAXN];
 int d[MAXM][MAXN],m,n,xx;
 int xL[MAXN],xR[MAXN];
 
 bool cmp(point A,point B)
 {
     if(A.x<B.x) return true;
     return false;
 }
 
 int find(int i,int key)
 {
     int L,R,M;
     L=0;R=n-1;
     while(L<=R)
     {
         M=(L+R)>>1;
         if(a[i][M].x<key) L=M+1;
         else if(a[i][M].x>key) R=M-1;
         else return M;
     }
     return L;
 }
 
 void work()
 {
     int i,j,k;
     sort(a[0],a[0]+n,cmp);
     for(i=0;i<n;i++)
         d[0][i]=abs(a[0][i].x-xx)+a[0][i].p;
     for(i=1;i<m;i++)
     {
         sort(a[i],a[i]+n,cmp);
         xL[0]=d[i-1][0]-a[i-1][0].x;
         for(j=1;j<n;j++)
         {
             xL[j]=min(d[i-1][j]-a[i-1][j].x,xL[j-1]);
         }
         xR[n-1]=d[i-1][n-1]+a[i-1][n-1].x;
         for(j=n-2;j>=0;j--)
         {
             xR[j]=min(d[i-1][j]+a[i-1][j].x,xR[j+1]);
         }
 
         for(j=0;j<n;j++)
         {
             k=find(i-1,a[i][j].x);
             if(k==n) d[i][j]=xL[n-1]+a[i][j].x+a[i][j].p;
             else if(k==0) d[i][j]=xR[0]-a[i][j].x+a[i][j].p;
             else
             {
                 if(a[i-1][k].x==a[i][j].x)
                     d[i][j]=min(xL[k]+a[i][j].x+a[i][j].p,xR[k]-a[i][j].x+a[i][j].p);
                 else
                     d[i][j]=min(xL[k-1]+a[i][j].x+a[i][j].p,xR[k]-a[i][j].x+a[i][j].p);
             }
         }
     }
 }
 
 int main()
 {
     int test,i,j;
     scanf("%d",&test);
     while(test--)
     {
         scanf("%d%d%d",&m,&n,&xx);
         for(i=0;i<m;i++)
             for(j=0;j<n;j++)
                 scanf("%d",&a[i][j].x);
         for(i=0;i<m;i++)
             for(j=0;j<n;j++)
                 scanf("%d",&a[i][j].p);
         work();
         int ans=1000000000;
         for(i=0;i<n;i++)
             if(ans>d[m-1][i])
                 ans=d[m-1][i];
         printf("%d\n",ans);
     }
     return 0;
 }

转载于:https://www.cnblogs.com/tim11/archive/2012/10/24/2737987.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值