运输小猫

2022/3/7 23:15:37

本文主要是介绍运输小猫,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

有m个猫 p个人 n个地点 每个点有若干只猫
每个猫会在\(t_i\)的时候可以开始被接走
每个人只能从1走到n 距离上要花费时间
求小猫等待时间的和的最小值

贪心来创造dp序:
可以先考虑没有距离的情况 然后把距离减到 构成等效时间

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
using namespace std;

const int N=1e5+10;
const ll INF=0x3f3f3f3f3f3f3f3f;
int read()
{
	int x=0,f=0,c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=1;c=getchar();}
	while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
	return f?-x:x;
}

int n,m,p;
ll d[N],h[N],t[N],a[N],sum[N],f[2][N];
int q[N],l,r;
//(x,f[i-1][x]+sum[x])
ll Y(int i,int x){return f[i^1][x]+sum[x];};

bool cmp_b(int i,int j1,int j2,int j3)
{
	return ( Y(i,j2)-Y(i,j1) )*(j3-j2)  >= ( Y(i,j3)-Y(i,j2) )*(j2-j1);
}

bool cmp_f(int i,int j1,int j2,ll k)
{
	return (Y(i,j2)-Y(i,j1)) <= k*(j2-j1); 
}

//n个地点 m只猫 p个人 
int main()
{
	n=read(); m=read(); p=read();
	for(int i=2;i<=n;i++) d[i]=d[i-1]+read();
	for(int i=1;i<=m;i++) h[i]=read(),t[i]=read();
	for(int i=1;i<=m;i++) a[i]=t[i]-d[h[i]];
	sort(a+1,a+m+1);
	for(int i=1;i<=m;i++) sum[i]=sum[i-1]+a[i];
	memset(f,0x3f,sizeof f);//初值还有防止赋值的作用
	f[0][0]=f[1][0]=0;	

// i&1 -> (i&1)^1
	for(int i=1;i<=p;i++)
	{
		bool now=i&1; 
		l=r=1; q[l]=0; 
		for(int j=1;j<=m;j++)
		{
			while(l<r&&cmp_f(now,q[l],q[l+1],a[j])) l++;
			f[now][j]=f[now^1][q[l]]+a[j]*(j-q[l])-(sum[j]-sum[q[l]]);
			while(l<r&&cmp_b(now,q[r-1],q[r],j)) r--;
			q[++r]=j;
		}
	}
	printf("%lld",f[p&1][m]);
	return 0;
}

注意: 在i=1的初值转移的时候 取min操作要通过合理赋值 来保证只能有一个值来转移
因此通常会用到无穷大无穷小的操作
取min的时候 在边界出 只有一个值能成功转移



这篇关于运输小猫的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程