校内测 U142298 出租车【dp】


题目:

传送门


题意:

n n n个人,每个人都有一个起点和终点,现在有一辆车载为 4 4 4人的车,每次移动一单位或上下车都会消耗一个单位时间,问在最优安排下,最少的时间花费是多少


分析:

根据 w y c wyc wyc大爷的说法,就是我们需要知道在任意时刻我们的车车在哪里,有哪些人,所以就有了如下的方程:
f i , s , w f_{i,s,w} fi,s,w表示当前已经考虑到 i i i,如今车上的人的下车点的状态是 s s s,车车现在在 w w w
有了 s s s,我们就可以表示出车上有几人,并且可以转移到他们下车的时候
说是状态,其实就是四元组嘛,但是,我们可以发现,对于 4 4 4个人会有 24 24 24中的排列,全是不同的状态怕是不妥,所以我们统一拍扁,变成从小到大的排列,这样还是相同的 4 4 4人,莫得影响,常数还变成了原来的 1 24 \frac{1}{24} 241


代码:

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define LL long long 
using namespace std;
inline LL read()
{
	LL s=0,f=1; char c=getchar();
	while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}
	while(c>='0'&&c<='9') {s=s*10+c-'0';c=getchar();}
	return s*f;
}
int a[15][15][15][15],b[15][15][15][15],cnt=0,r[5];
int f[2][1500][11],q[1500][5];
int main()
{
	int n=read(),k=read();
	for(int x1=0;x1<=k;x1++)
	  for(int x2=x1;x2<=k;x2++)
	    for(int x3=x2;x3<=k;x3++)
	      for(int x4=x3;x4<=k;x4++)
	      {
	        a[x1][x2][x3][x4]=++cnt;
		  	q[cnt][1]=x1;q[cnt][2]=x2;q[cnt][3]=x3;q[cnt][4]=x4;
		  }
	for(int x1=0;x1<=k;x1++)
	  for(int x2=0;x2<=k;x2++)
	    for(int x3=0;x3<=k;x3++)
	      for(int x4=0;x4<=k;x4++)
	      {
	      	r[1]=x1;r[2]=x2;r[3]=x3;r[4]=x4;
	      	sort(r+1,r+5);
	      	b[x1][x2][x3][x4]=a[r[1]][r[2]][r[3]][r[4]];
		  }
	int o=0;
	memset(f[o],0x3f,sizeof(f[o]));
	f[0][1][1]=0;	
	for(int ij=1;ij<=n;ij++)
	{
		o^=1;
		memset(f[o],0x3f,sizeof(f[o]));
		int x=read(),y=read();
		for(int s=1;s<=cnt;s++)
		{
			if(q[s][1]) continue;
			int t=b[y][q[s][2]][q[s][3]][q[s][4]];
			for(int w=1;w<=k;w++)
			  f[o][t][x]=min(f[o][t][x],f[o^1][s][w]+abs(w-x)+1);
		}
		for(int s=cnt;s;s--)
		{
			int t;
			if(q[s][1]) 
			{
				t=b[0][q[s][2]][q[s][3]][q[s][4]];
				for(int w=1;w<=k;w++)
				  f[o][t][q[s][1]]=min(f[o][t][q[s][1]],f[o][s][w]+abs(w-q[s][1])+1);
			}
			if(q[s][2]) 
			{
				t=b[q[s][1]][0][q[s][3]][q[s][4]];
				for(int w=1;w<=k;w++)
				  f[o][t][q[s][2]]=min(f[o][t][q[s][2]],f[o][s][w]+abs(w-q[s][2])+1);
			}
			if(q[s][3]) 
			{
				t=b[q[s][1]][q[s][2]][0][q[s][4]];
				for(int w=1;w<=k;w++)
				  f[o][t][q[s][3]]=min(f[o][t][q[s][3]],f[o][s][w]+abs(w-q[s][3])+1);
			}
			if(q[s][4]) 
			{
				t=b[q[s][1]][q[s][2]][q[s][3]][0];
				for(int w=1;w<=k;w++)
				  f[o][t][q[s][4]]=min(f[o][t][q[s][4]],f[o][s][w]+abs(w-q[s][4])+1);
			}
		}
	}
	int ans=2147483647;
	for(int w=1;w<=k;w++) ans=min(ans,f[o][1][w]);
	cout<<ans;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值