AOJ543 Mobile Service

题目连接http://icpc.ahu.edu.cn/OJ/Problem.aspx?id=543

Description
一个公司有三个移动服务员。如果某个地方有一个请求,某个员工必须赶到那个地方去(那个地方没有其他员工),某一时刻只有一个员工能移动。被请求后,他才能移动,不允许在同样的位置出现两个员工。从p到q移动一个员工,需要花费c(p,q)。这个函数没有必要对称,但是c(p,p)=0。公司必须满足所有的请求。目标是最小化公司花费。

Input
第一行有两个整数L,N(3<=L<=200, 1<=N<=1000)。L是位置数 ;N是请求数。每个位置从1到L编号。下L行每行包含L个非负整数。第i+1行的第j个数表示c(i,j) ,并且它小于2000。最后一行包含N个数,是请求列表。一开始三个服务员分别在位置1,2,3。

Output
一个数M,表示最小服务花费。


乍一看,DP,但是规模太大 200*200*200*1000,然后想搜索剪枝,没有好的Idea


仔细想想,发现其实DP状态没有那么多,因为题目貌似隐含了,每次走只能往客户那边走,不能随便走,所以每次走过后,肯定有一个人的位置是确定的,就是在客户那儿,于是状态数就变成了200*200*1000,依然纠结能不能过~但是看到3s的限制,感觉差不多吧


dp[k][i][j] 表示第k个客户,另外两个人在i,j位置的最小花费。k用滚动数组压缩下。

保证i<j,但是依然不知道客户相对于i,j的位置,于是出现了下面代码中 大量的判断,以及代码copy冗余,看着都渗人。。


代码幸亏写的还算可以~~没出错~~不然根本改不出来~~大家瞅瞅就知道了~~


#include <stdio.h>

#define INF 100000000

int N,L,ans;
int c[205][205];//价值矩阵
int cal[1005];//请求序列
int dp[2][205][205];


void copy2(int a,int b)
{
	int i,j;

	for (i=1;i<=L;++i)
	{
		for (j=1;j<=L;++j)
		{
			dp[b][i][j]=dp[a][i][j];
		}
	}
}
void clr(int cur)
{
	int i,j;

	for (i=1;i<=L;++i)
	{
		for (j=1;j<=L;++j)
		{
			dp[cur][i][j]=INF;
		}
	}
}

void work()
{
	int i,j,cur,k,pre;

	//initial
	clr(0);

	cal[0]=1;
	dp[0][2][3]=0;

	//work
	for (k=1;k<=N;++k)
	{
		cur=k%2;
		pre=1-cur;

		//两次重叠,不需要移动
		if (cal[k] == cal[k-1])
		{
			copy2(pre,cur);
			continue;
		}

		//清理
		clr(cur);
		//non 
		for (i=1;i<=L;++i)
		{
			for (j=i+1;j<=L;++j)
			{
				if (dp[pre][i][j] == INF) continue; //状态不可达
				if (i == cal[k-1]  || j==cal[k-1]) continue; //错误状态,一开始忘记加,WA了一次
				if (cal[k]==i)
				{
					if (j<cal[k-1] && dp[pre][i][j]<dp[cur][j][cal[k-1]])
					{
						dp[cur][j][cal[k-1]]=dp[pre][i][j];
					}else if (j>cal[k-1] && dp[pre][i][j]<dp[cur][cal[k-1]][j])
					{
						dp[cur][j][cal[k-1]]=dp[pre][i][j];
					}
				}
				if (cal[k]==j)
				{
					if (i<cal[k-1] && dp[pre][i][j]<dp[cur][i][cal[k-1]])
					{
						dp[cur][i][cal[k-1]]=dp[pre][i][j];
					}else if (i>cal[k-1] && dp[pre][i][j]<dp[cur][cal[k-1]][i])
					{
						dp[cur][i][cal[k-1]]=dp[pre][i][j];
					}
				}
				//other
				if (cal[k-1] < i)
				{
					if (dp[pre][i][j]+c[i][cal[k]] < dp[cur][cal[k-1]][j])
					{
						dp[cur][cal[k-1]][j]=dp[pre][i][j]+c[i][cal[k]];
					}
					if (dp[pre][i][j]+c[j][cal[k]] < dp[cur][cal[k-1]][i])
					{
						dp[cur][cal[k-1]][i]=dp[pre][i][j]+c[j][cal[k]];
					}
					if (dp[pre][i][j]+c[cal[k-1]][cal[k]] < dp[cur][i][j])
					{
						dp[cur][i][j] = dp[pre][i][j]+c[cal[k-1]][cal[k]];
					}
				}else if ( cal[k-1] < j)
				{
					if (dp[pre][i][j]+c[i][cal[k]] < dp[cur][cal[k-1]][j])
					{
						dp[cur][cal[k-1]][j]=dp[pre][i][j]+c[i][cal[k]];
					}
					if (dp[pre][i][j]+c[j][cal[k]] < dp[cur][i][cal[k-1]])
					{
						dp[cur][i][cal[k-1]]=dp[pre][i][j]+c[j][cal[k]];
					}
					if (dp[pre][i][j]+c[cal[k-1]][cal[k]] < dp[cur][i][j])
					{
						dp[cur][i][j] = dp[pre][i][j]+c[cal[k-1]][cal[k]];
					}
				}else
				{
					if (dp[pre][i][j]+c[i][cal[k]] < dp[cur][j][cal[k-1]])
					{
						dp[cur][j][cal[k-1]]=dp[pre][i][j]+c[i][cal[k]];
					}
					if (dp[pre][i][j]+c[j][cal[k]] < dp[cur][i][cal[k-1]])
					{
						dp[cur][i][cal[k-1]]=dp[pre][i][j]+c[j][cal[k]];
					}
					if (dp[pre][i][j]+c[cal[k-1]][cal[k]] < dp[cur][i][j])
					{
						dp[cur][i][j] = dp[pre][i][j]+c[cal[k-1]][cal[k]];
					}
				}
			}
		}
	}

	ans=INF;
	for (i=1;i<=L;++i)
	{
		for (j=1;j<=L;++j)
		{
			if (dp[cur][i][j] < ans)
			{
				ans=dp[cur][i][j];
			}
		}
	}

}

int main()
{
	int i,j;
	
	scanf("%d%d",&L,&N);

	for (i=1;i<=L;++i)
	{
		for (j=1;j<=L;++j)
		{
			scanf("%d",c[i]+j);
		}
	}
	for (i=1;i<=N;++i)
	{
		scanf("%d",cal+i);
	}
	work();
	printf("%d",ans);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值