题意:

有一个n*m的矩阵,左右可以随便走,但只能在每一行的中点往下走,每走一格花费时间1.

现在这个矩阵里放了k瓶牛奶,第i个牛奶喝下去需要ti时间

起点是(1,1)

对于每个i∈[1,k],问喝掉k瓶牛奶花费的最小时间

题解:

首先离散化行。

记第 i 行的牛奶数为 ci,则对于第 i 行,求出在行内向左/右走喝 1,2,...,ci 包牛奶并 且回到/不回到行中点的最短时间,然后合并背包求出在第 i 行内喝 1,2,...,ci 包牛奶并且 回到/不回到行中点的最短时间,然后和在前 i−1 行喝牛奶并回到中点的背包合并,求出 在前 i 行内喝 1,2,...,k 包牛奶并且回到/不回到行中点的最短时间,并用不回到中点的背包 更新答案。每一行处理的复杂度为 O(kci),因此总复杂度为 O(k2)。

注意对第一行因为是从最左边而不是中间开始,所以要特殊处理。

#include<bits/stdc++.h>
#define MAXN 10004
#define LL long long
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
struct Milk{
int x,y,t;
friend bool operator >(const Milk &a,const Milk &b){
return a.y>b.y;
}
friend bool operator <(const Milk &a,const Milk &b){
return a.y<b.y;
} Milk(){}
Milk(int a,int b,int c){
x=a;y=b;t=c;
}
}milk[MAXN];
vector<LL> solve(const vector<Milk> &a,int dest){
//调用引用,减小常数
//背包算出停在dest点花费最小时间
//若dest为0则不限制停在哪一点
vector<LL> c(a.size(),INF);
vector<LL> t(a.size(),INF);
c[]=(dest==-)?:abs(dest-a[].y);
t[]=;
for(int i=;i<a.size();++i){
int len=abs(a[i].y-a[i-].y);
for(int j=;j<i;++j)t[j]+=len;
for(int j=i;j>=;--j)t[j]=min(t[j],t[j-]+a[i].t);
for(int j=;j<=i;++j){
LL tmp=t[j]+(dest==-?:abs(dest-a[i].y));
c[j]=min(c[j],tmp);
}
}
return c;
}
vector<LL> Merge(const vector<LL> &a,const vector<LL> &b){
vector<LL> c(a.size()+b.size()-,INF);
for(int i=;i<a.size();++i){
for(int j=;j<b.size();++j){
c[i+j]=min(c[i+j],a[i]+b[j]);
}
}
//两个参数分别是朝向两个方向喝多少瓶牛奶花费最少时间,把这俩合并
return c;
}
int main(){
int T;
scanf("%d",&T);
while(T--){
int n,m,k;
scanf("%d %d %d",&n,&m,&k);
vector<int> disc;
disc.push_back();
for(int i=;i<=k;i++){
scanf("%d %d %d",&milk[i].x,&milk[i].y,&milk[i].t);
disc.push_back(milk[i].x);
}
sort(disc.begin(),disc.end());
disc.erase(unique(disc.begin(),disc.end()),disc.end());
//去重
vector<Milk> a[MAXN];
LL Ans[MAXN];
for(int i=;i<disc.size();++i)a[i].clear(); for(int i=;i<=k;++i){
int tmp=lower_bound(disc.begin(),disc.end(),milk[i].x)-disc.begin();
a[tmp].push_back(milk[i]);
Ans[i]=INF;
}
//将行离散化
for(int i=;i<disc.size();++i){
sort(a[i].begin(),a[i].end());
}
vector<LL> f[];//存储结果
vector<Milk> t=a[];//存储当前行 t.insert(t.begin(),Milk(,,)); f[]=solve(t,(m+)/);
vector<LL> g=solve(t,-);
for(int i=;i<t.size();++i)Ans[i]=min(Ans[i],g[i]); for(int i=;i<disc.size();++i) {
vector<Milk>::iterator sp=lower_bound(a[i].begin(),a[i].end(),Milk(i,(m+)/,));
vector<Milk> t0(a[i].begin(),sp);
vector<Milk> t1(sp,a[i].end()); t0.push_back(Milk(i,(m+)/,));
reverse(t0.begin(),t0.end()); t1.insert(t1.begin(),Milk(i,(m+)/,)); vector<LL> f0,f1,g0,g1;
f0=solve(t0,(m+)/);
f1=solve(t1,(m+)/);
g0=solve(t0,-);
g1=solve(t1,-);
//向两个方向分别背包 g0=Merge(f1,g0);
g1=Merge(f0,g1); vector<LL> g(g0.size()); for(int j=;j<g.size();++j){
g[j]=min(g0[j],g1[j]);
} g=Merge(f[(i-)&],g);
//把每层的背包合并 f[i&]=Merge(f[(i-)&],Merge(f0,f1)); for(int j=;j<g.size();++j) {
Ans[j]=min(Ans[j],g[j]+=disc[i]-disc[i-]);
f[i&][j]+=disc[i]-disc[i-];
}
} for(int i=;i<k;i++){
printf("%lld ",Ans[i]);
}
printf("%lld\n",Ans[k]);
}
}

最新文章

  1. java学习之面向对象(2)
  2. Uiautomator 2.0之Configrator类学习小记
  3. HTML 事件属性
  4. Js练习题之查找字符串中出现最多的字符和个数
  5. VirtualBox 给虚拟机绑定IP
  6. [Jest] Test JavaScript with Jest
  7. 数据库备份,远程执行SHELL脚本
  8. GCC扩展(转--对看kernel代码有帮助
  9. cocos2dx Menu
  10. protobuf 参考资料
  11. 鼠标拖放div 实现
  12. Chrome设计文档-多进程资源加载
  13. 初探swift语言的学习笔记五(线程)
  14. phpcms 制作简单企业站的常用标签
  15. python requests 官方文档
  16. 2017 Multi-University Training Contest - Team 9 1002&amp;&amp;HDU 6162 Ch’s gift【树链部分+线段树】
  17. k8s踩坑记 - kubeadm join 之 token 失效
  18. RTX 无法刷新组织架构的处理方法总结
  19. 【Consul】CONSUL调研
  20. Web挂马方式整理

热门文章

  1. vue $emit 子传父
  2. Deployment的使用
  3. python-面向对象-01课堂笔记
  4. Bootstrap4入门
  5. GetWindowLong
  6. NX二次开发-UFUN获取显示在NX交互界面的对象UF_OBJ_is_displayable
  7. NX二次开发-删除功能区工具栏UF_UI_remove_ribbon
  8. macOS cataline 10.15 升级后问题一览
  9. flutter 图片为空报错
  10. 知识整理:字符串hash