P4046 [JSOI2010]快递服务

题目链接 双倍经验

大致题意

\(m\)个位置,从位置\(p\)移动到位置\(q\)需要花费\(c(p,q)\)的价钱,但并不保证\(c(p,q)≠c(q,p)\)

现在有三个员工,初始位置在\(1,2,3\)和有\(n\)个请求,任何时刻只有一名员工可以移动,且不允许同一位置上有 \(2\) 个以上员工。第 \(i\) 个请求发生在位置 \(p_i\),公司必须按照顺序,派一名员工到位置 \(p_i\)去完成请求

求公司的最小花费。

分析

\(f(i,x,y,z)\)表示解决完前\(i\)个请求时,三个员工分别在\(x,y,z\)处时的最小花费,转移:

\(f(i+1,p_{i+1},y,z) = min\{f(i,x,y,z)+c(x,p_{i+1})\}\qquad (p_{i+1}≠y≠z)\)

\(f(i+1,x,p_{i+1},z) = min\{f(i,x,y,z)+c(y,p_{i+1})\}\qquad (x≠p_{i+1}≠z)\)

\(f(i+1,x,y,p_{i+1}) = min\{f(i,x,y,z)+c(z,p_{i+1})\}\qquad (x≠y≠p_{i+1})\)

时空复杂度\(O(nm^3)\),无论是在时间上还是空间上都接受不了

考虑优化:

可以发现,在完成第\(i\)个任务时,一定有一个人站在\(p_i\)的位置上,也就是说,这个人的信息是"多余"的,只需要记录另外两个人的位置

\(f(i,x,y)\)表示解决前\(i\)个请求时,三个员工分别在\(x,y,p_i\)时的最小花费,转移:

\(f(i+1,p_i,y) = min\{f(i,x,y)+c(x,p_{i+1})\}\qquad (p_i≠y≠p_{i+1})\)

\(f(i+1,x,y) = min\{f(i,x,y)+c(p_i,p_{i+1})\}\qquad (x≠y≠p_{i+1})\)

\(f(i+1,x,p_i) = min\{f(i,x,y)+c(y,p_{i+1})\}\qquad (x≠p_i≠p_{i+1})\)

时间复杂度\(O(nm^2)\),再用滚动数组优化一下空间即可

\(code\)

/*
xcxc82
*/
#include<bits/stdc++.h>
using namespace std;
#define inf 1e9+10
const int MAXN = 210;
int T,L,n;
inline int read(){
	int X=0; bool flag=1; char ch=getchar();
	while(ch<'0'||ch>'9') {if(ch=='-') flag=0; ch=getchar();}
	while(ch>='0'&&ch<='9') {X=(X<<1)+(X<<3)+ch-'0'; ch=getchar();}
	if(flag) return X;return ~(X-1);
}
int f[2][MAXN][MAXN];
int val[MAXN][MAXN],a[MAXN*5];
int main(){
		memset(f,0x3f,sizeof(f));
		L = read();
		for(int i=1;i<=L;i++){
			for(int j=1;j<=L;j++){
				val[i][j] = read();
			}
		}
	    a[0] = 3;
		f[0][1][2] = 0;
		int now;
		while(cin>>now) a[++n] = now;
		for(int i=0;i<=n-1;i++){
			memset(f[i+1&1],0x3f,sizeof(f[i+1&1]));
			for(int x=1;x<=L;x++){
				for(int y=1;y<=L;y++){
					if(x==y||x==a[i]||y==a[i]) continue;
					f[i+1&1][a[i]][y] = min(f[i+1&1][a[i]][y],f[i&1][x][y]+val[x][a[i+1]]);
					f[i+1&1][x][y] = min(f[i+1&1][x][y],f[i&1][x][y]+val[a[i]][a[i+1]]);
					f[i+1&1][x][a[i]] = min(f[i+1&1][x][a[i]],f[i&1][x][y]+val[y][a[i+1]]);
				}
			}
		}
		int ans = 0x3f3f3f3f;
		
		for(int i=1;i<=L;i++) 
		 for(int j=1;j<=L;j++) 
		  ans = min(ans,f[n&1][i][j]);
		  
		printf("%d",ans);
   return 0;
}






posted @ 2021-01-24 21:59  xcxc82  阅读(48)  评论(0编辑  收藏  举报