码迷,mamicode.com
首页 > 其他好文 > 详细

UVALive-3983 Robotruck

时间:2017-10-16 23:31:41      阅读:189      评论:0      收藏:0      [点我收藏+]

标签:space   ios   uva   push   前缀和   col   cpp   std   size   

题目大意:

二维平面上有一些点, 每个点上有一个垃圾, 重量为w; 有一个机器人, 能承载的重量最多为c, 从原点出发, 要把所有的垃圾带回原点( 中途可以放一些回来 ), 每次都走曼哈顿距离, 求把所有垃圾放回原点走的最小距离.

首先看一下, 这个题目不是很好写啊.

尝试设一下状态, 设dp[ i ]为把第i个垃圾放到垃圾桶里面的最小代价, 那么我们枚举一下j, 把j+1到i的所有垃圾一次性全部放入垃圾桶作为转移( 前提是j+1到i的重量和要小于等于c ).

那么我们就得到了转移方程:

dp[ i ]=min( dp[ j ]+sum_dis[ j+1 ][ i ]+len[ j+1 ]+len[ i ]), 要求sum_w[ j+1 ][ i ]<=c.

其中sum_dis}[ j+1 ][ i ]表示从第j+1个垃圾的位置走到第i个垃圾的位置的距离之和, sum_w[ j+1 ][ i ]表示j+1到i的重量和, len[ i ]表示第i个垃圾到垃圾桶( 原点 )的距离.

一如既往地把sum搞成前缀和, 展开式子可以得到:

dp[ i ]=min( dp[ j ]+sum_dis[ i ]-sum_dis[ j+1 ]+len[ j+1 ]+len[ i ] ), 要求sum_w[ i ]-sum_w[ j ]<=c.

( 为什么只减sum_dis[ j+1 ]就可以了? 因为sum_dis[ x ]记录的是从第1个垃圾的位置开始走, 走到第x个垃圾的总距离, 减到j+1就是从j+1走到i的距离了 );

再把和j无关的提出来:

dp[ i ]=min( dp[ j ]-sum_dis[ j+1 ]+len[ j+1 ] )+len[ i ]+sum_dis[ i ],

那么我们设f[ i ]=dp[ j ]-sum_dis[ j+1 ]+len[ j+1 ], 把i丢到一个按f[ i ]单调递增的单调队列里面, 每次取出队首, 如果队首到i的重量和大于c就弹掉, 得到当前dp[ i ]就可以得到f[ i ], 把i丢到单调队列里面就可以了, 这样时间就是O( n )的了;

或者丢到堆里面, 就是O( nlogn ), 因为慢, 我没写.

代码如下:

//made by Crazy01
#include<queue>
#include<math.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#define inf 1<<30
#define ll long long
#define db double
#define c233 cout<<"233"<<endl
#define mem(s) memset(s,0,sizeof(s))
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
const int N=100050;
using namespace std;

int dp[N],sum_dis[N],len[N],f[N],sum_w[N],X[N],Y[N];
int n,c,T;
struct lll{
  int q[N];
  int hd,tl;
  bool empty(){return hd>=tl;}
  void clear(){hd=0,tl=1;q[0]=0;}
  int top(){return empty()?0:q[hd];}
  void pop(){hd++;}
  void push(int x){
    while(tl>hd&&f[q[tl-1]]>f[x])tl--;
    q[tl++]=x;
  }
}q;

inline int gi(){
  int x=0,res=1;char ch=getchar();
  while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)res*=-1;ch=getchar();}
  while(ch<=‘9‘&&ch>=‘0‘)x=(x<<1)+(x<<3)+ch-48,ch=getchar();
  return x*res;
}

inline void init(){
  c=gi(); n=gi();
  for(int i=1;i<=n;i++){
    X[i]=gi(); Y[i]=gi();
    int a=gi();
    len[i]=abs(X[i])+abs(Y[i]);
    sum_dis[i]=sum_dis[i-1]+abs(X[i]-X[i-1])+abs(Y[i]-Y[i-1]);
    sum_w[i]=a+sum_w[i-1];
  }
}

inline int func(int i){
  return dp[i]-sum_dis[i+1]+len[i+1];
}

inline void work(){
  for(int i=1;i<=n;i++){
    while(sum_w[i]-sum_w[q.top()]>c&&!q.empty())q.pop();
    dp[i]=f[q.top()]+sum_dis[i]+len[i];
    f[i]=func(i);
    q.push(i);
  }
  printf("%d\n",dp[n]);
  if(T)cout<<endl;
}

int main(){
  T=gi();
  while(T--){
    q.clear();
    init();
    work();
  }
  return 0;
}

UVALive-3983 Robotruck

标签:space   ios   uva   push   前缀和   col   cpp   std   size   

原文地址:http://www.cnblogs.com/Crazy01/p/7679155.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!