[UVALive 3983] Robotruck

图片加载可能有点慢,请跳过题面先看题解,谢谢
1196604-20171013115021777-1104298518.png
1196604-20171013115026684-110030556.png
1196604-20171013115031527-178826682.png

设状态 \(f[i][j]\) 为,当前垃圾序号为 \(i\) ,当前承重为 \(j\) 的最小路程,好的这道题做完了
O(NC) G烂
$
$
我们这样设: \(f[i]\) 为,从起点出发,将前 \(i\) 个垃圾清完并放进垃圾桶的最小路程
显然有转移:\(f[i]=min(f[j]+H[j+1]+dis[j+1][i]+H[i]),j\le i,sum[j+1][i]<=c\),其中,
\(sum[i][j]\) 为第 \(i\) 个垃圾到第 \(j\) 个垃圾的重量和,\(H[i]\) 为垃圾 \(i\) 到原点的距离,\(dis[i][j]\) 为从第 \(i\) 个垃圾出发,依次经过第 \(i+1,i+2...j\) 个垃圾的总路程
我们将上面的式子转换一下,设 \(t[i]\) 为,从第 \(1\) 个垃圾出发,依次经过第 \(2,3,4...i\) 个垃圾的总路程,
则有:\(dis[i][j]=t[j]-t[i]\)
所以:\(f[i]=min(f[j]-t[j+1]+H[j+1])+t[i]+H[i],sum[j+1][i]<=c\)
令:\(calc(j)=f[j]-t[j+1]+H[j+1]\),所以有:\(f[i]=min(calc(j))+t[i]+H[i],sum[j+1][i]<=c\)
这个式子。。。用什么数据结构都能维护。。。\(XJB\) 搞一下就能 \(AC\)
$
$
这里用到单调队列,时间复杂度:\(O(n)\)

//made by Hero_of_Someone
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#define N (100010)
#define il inline
#define RG register
using namespace std;
il int gi(){ RG int x=0,q=1; RG char ch=getchar(); while( ( ch<'0' || ch>'9' ) && ch!='-' ) ch=getchar();
  if( ch=='-' ) q=-1,ch=getchar(); while(ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); return q*x; }

int T,n,c;
int x[N],y[N];
int t[N],S[N],H[N];
int que[N],f[N];

il void init(){
   c=gi(),n=gi();
   for(RG int i=1;i<=n;i++){
      x[i]=gi(),y[i]=gi(); int w=gi();
      H[i]=abs(x[i])+abs(y[i]);
      t[i]=t[i-1]+abs(x[i]-x[i-1])+abs(y[i]-y[i-1]);
      S[i]=S[i-1]+w;
   }
}

il int calc(int x){return f[x]-t[x+1]+H[x+1];}

il void work(){
   int hd=0,tl=0;
   for(RG int i=1;i<=n;i++){
      while(hd<=tl && S[i]-S[que[hd]]>c) hd++;
      f[i]=calc(que[hd])+t[i]+H[i];
      while(hd<=tl && calc(i)<=calc(que[tl])) tl--;
      que[++tl]=i;
   }
   printf("%d\n",f[n]); if(T)puts("");
}

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

$
$
附,优先队列的代码,时间复杂度:\(O(nlogn)\)

//made by Hero_of_Someone
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<queue>
#include<cmath>
#define N (100010)
#define il inline
#define RG register
using namespace std;
il int gi(){ RG int x=0,q=1; RG char ch=getchar(); while( ( ch<'0' || ch>'9' ) && ch!='-' ) ch=getchar();
  if( ch=='-' ) q=-1,ch=getchar(); while(ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); return q*x; }

int T,n,c;
int x[N],y[N];
int t[N],S[N],H[N];
int f[N];

il void init(){
   c=gi(),n=gi();
   for(RG int i=1;i<=n;i++){
      x[i]=gi(),y[i]=gi(); int w=gi();
      H[i]=abs(x[i])+abs(y[i]);
      t[i]=t[i-1]+abs(x[i]-x[i-1])+abs(y[i]-y[i-1]);
      S[i]=S[i-1]+w;
   }
}

struct R{int id,x;
   il bool operator<(const R &a)const{return x>a.x;}
}a;
priority_queue<R>que;

il void work(){ 
   while(!que.empty()) que.pop(); 
   que.push(a);
   for(RG int i=1;i<=n;i++){
      R x=que.top();
      while(!que.empty()&&S[i]-S[x.id]>c) que.pop(),x=que.top();
      f[i]=x.x+t[i]+H[i];
      que.push((R){i,f[i]-t[i+1]+H[i+1]});
   }
   printf("%d\n",f[n]); if(T)puts("");
}

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

$
$
另附,在vjudge上跑的比STL还慢的手写堆代码:

//made by Hero_of_Someone
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<queue>
#include<cmath>
#define N (100010)
#define il inline
#define RG register
using namespace std;
il int gi(){ RG int x=0,q=1; RG char ch=getchar(); while( ( ch<'0' || ch>'9' ) && ch!='-' ) ch=getchar();
  if( ch=='-' ) q=-1,ch=getchar(); while(ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); return q*x; }

int T,n,c;
int x[N],y[N];
int t[N],S[N],H[N];
int f[N],dis[N];

struct heap{
#define fa (x>>1)
#define ls (x<<1)
#define rs (x<<1|1)
  
  int a[N],id[N],len;

  il int top(){ return a[1]; }

  il void push(RG int u){
    if(!id[u]) id[u]=++len,a[len]=u; RG int x=id[u];
    while(fa){
      if(dis[a[x]]>=dis[a[fa]]) break;
      swap(a[x],a[fa]),id[a[x]]=x,id[a[fa]]=fa,x=fa;
    }
    return;
  }
  
  il void pop(){
    id[a[1]]=0,a[1]=a[len--]; if (len) id[a[1]]=1; RG int x=1,son;
    while(ls<=len){
      son=(rs<=len && dis[a[rs]]<dis[a[ls]]) ? rs : ls;
      if(dis[a[x]]<=dis[a[son]]) break;
      swap(a[x],a[son]),id[a[x]]=x,id[a[son]]=son,x=son;
    }
    return;
  }
  
#undef fa
#undef ls
#undef rs  
}que;

il void init(){
   c=gi(),n=gi();
   for(RG int i=1;i<=n;i++){
      x[i]=gi(),y[i]=gi(); int w=gi();
      H[i]=abs(x[i])+abs(y[i]);
      t[i]=t[i-1]+abs(x[i]-x[i-1])+abs(y[i]-y[i-1]);
      S[i]=S[i-1]+w;
   }
}

il void work(){ 
   while(que.len) que.pop(); 
   que.push(0);
   for(RG int i=1;i<=n;i++){
      int x=que.top();
      while(que.len&&S[i]-S[x]>c) que.pop(),x=que.top();
      f[i]=dis[x]+t[i]+H[i];
      dis[i]=f[i]-t[i+1]+H[i+1]; que.push(i);
   }
   printf("%d\n",f[n]); if(T)puts("");
}

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

转载于:https://www.cnblogs.com/Hero-of-someone/p/7660442.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值