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);
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章