ZOJ 1232

題目意思很簡單:
有A個村子和B個城堡,村子標號是1~A,城堡標號是A+1~B。馬里奧現在位於城堡B,他要帶公主回到村子1,他有一雙靴子,穿上之後可以不用時間就能從一個地方飛到另外一個地方,但是穿着靴子不能穿過城堡,穿靴子的次數也不能超過 K 次,一次不能超過 L km。求從 B 到 1 所用的最短時間。
分析:
最開始是在一本書上看到這道題目,說是Dijstra,於是打算來寫寫看。結果悲劇了。題目的關鍵點其實是在哪裏使用鞋子才能使得全局的時間最少,可以用 DP 來解決,用一種逆向思維,先來寫動態轉移方程,用 i 來表示目前到了 i 點,用 j 來表示到 i 點時穿了幾次靴子,dp[i][j] = min{dp[k][j-1],dp[k][j]+map[k][i]} 從方程中可以看出,需要知道任意兩個點之間的距離,也需要知道任意兩個點之間是否能夠穿靴子通過(比如考慮到 K,L),此時就需要用到求最短路徑了,由於此時用到的是任意兩個點之間的最短路徑,所以最好用 Floyd ,用 Dijstra 的話在求任意兩個點之間是否能夠穿靴子通過時就會出現點小麻煩。
好吧,其實我兩種都寫了。

貼下Dijstra的代碼

#include<stdio.h>
const int maxn = 150;
const int INF = 1000000000;
int mat[maxn][maxn],tmp[maxn][maxn],Dist[maxn];
int DP[maxn][20],newmat[maxn][maxn];
bool visited[maxn];
int n,A,B,L;
void Dijstra(int s)
{
	int i,j,k,min;
	for(i=1;i<=n;i++)
	{
		Dist[i] = mat[s][i];
		visited[i] = false;
	}
	Dist[s] = 0;
	visited[s] = true;
	for(i=1;i<=n;i++)
	{
		k = -1;
		min = INF;
		for(j=1;j<=n;j++)
			if(visited[j]==false&&min>Dist[j])
			{
				k = j;
				min = Dist[j];
			}
			if(k!=-1)
			{
				visited[k] = true;
				for(j=1;j<=n;j++)
				{
					if(Dist[k]+mat[k][j]<Dist[j])
					{
						Dist[j] = Dist[k] + mat[k][j];
					}
				}
			}
	}
}

void Dijstra1(int s)//爲了求tmp[][],tmp[][]保存的是任意兩點是否能穿鞋子通過。
{
	int i,j,k,min;
	for(i=1;i<=n;i++)
	{
		Dist[i] = mat[s][i];
		visited[i] = false;
	}
	Dist[s] = 0;
	visited[s] = true;
	for(i=1;i<=n;i++)
	{
		k = -1;
		min = INF;
		for(j=1;j<=n;j++)
			if(visited[j]==false&&min>Dist[j])
			{
				k = j;
				min = Dist[j];
			}
			if(k!=-1)
			{
				visited[k] = true;
				for(j=1;j<=n;j++)
				{
					if(Dist[k]+mat[k][j]<Dist[j]&&k<=A)
					{	
						Dist[j] = Dist[k]+mat[k][j];
						if(Dist[j]<=L)
							tmp[s][j] = 0;
					}
				}
			}
	}
}
int main()
{
	int i,j,t,m,K;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d%d%d%d",&A,&B,&m,&L,&K);
		n = A+B;
		for(i=1;i<=n;i++)
			for(j=1;j<=n;j++)
				mat[i][j] = newmat[i][j] = tmp[j][i] = INF;//初始化
			int a,b,c;
			for(i=0;i<m;i++)
			{
				scanf("%d%d%d",&a,&b,&c);
				mat[a][b] = mat[b][a] = c;
				if(c<=L)
					tmp[a][b] = tmp[b][a] = 0;
				newmat[a][b] = newmat[b][a] = c;
			}//構圖
			for(i=1;i<=n;i++)
			{
				Dijstra1(i);
				Dijstra(i);
				for(j=1;j<=n;j++)
					newmat[i][j] = Dist[j];
			}
			for(i=1;i<=n;i++)
				DP[i][0] = newmat[1][i];//未使用加速靴時的時間
			for(j=1;j<=K;j++)
				DP[1][j] = 0;
		    for(i=2;i<=n;i++)	
			{
				for(j=1;j<=K;j++)
				{
					int min = INF,tt;
					for(int l = 1;l<i;l++)
					{
						if(!tmp[l][i])
							tt = DP[l][j-1]>DP[l][j]+newmat[l][i]?DP[l][j]+newmat[l][i]:DP[l][j-1];
						else 
							tt = newmat[l][i]+DP[l][j];
						if(tt<min)
							min = tt;
					}
					DP[i][j] = min;
				}
			}
			printf("%d\n",DP[n][K]);
			
	}
	return 0;
}
再來比對一下Floyd的代碼
#include<stdio.h>
const int maxn = 150;
const int INF = 1000000000;
int dp[maxn][20],mat[maxn][maxn],mind[maxn][maxn],tmp[maxn][maxn];
int n,A,B,L;
void Floyd()
{
	int i,j,k;
	for(i=1;i<=n;i++)
		for(j=1;j<=n;j++)
			mind[i][j] = mat[i][j];
	for(k=1;k<=n;k++)
	{
		for(i=1;i<=n;i++)
		{
			for(j=1;j<=n;j++)
			{
				if(mind[i][k]+mind[k][j]<mind[i][j])
				{
					mind[i][j] = mind[i][k] + mind[k][j];
					if(k<=A&&mind[i][j]<=L)
						tmp[i][j] = 1;
				}
			}
		}
	}

}
int main()
{
	int t,K,m,i,j,a,b,c;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d%d%d%d",&A,&B,&m,&L,&K);
		n = A+B;
		for(i=1;i<=n;i++)
		{
			for(j=1;j<=n;j++)
			{
				if(i==j)
					mat[i][j] = 0;
				else
					mat[i][j] = INF;
				tmp[i][j] = 0;
			}
		}//初始化
		for(i=1;i<=m;i++)
		{
			scanf("%d%d%d",&a,&b,&c);
			mat[a][b] = mat[b][a] = c;
			if(c<=L)
				tmp[a][b] = tmp[b][a] = 1;
		}//初步構圖
		Floyd();//mind[][]保存計算之後的最短路徑
		for(i=1;i<=n;i++)
			dp[i][0] = mind[1][i];
		for(i=1;i<=K;i++)
			dp[1][i] = 0;
		for(i=2;i<=n;i++)
		{
			for(j=1;j<=K;j++)
			{
				int min = INF,tt;
				for(int l=1;l<i;l++)
				{
					if(tmp[l][i])
						tt = dp[l][j-1]<dp[l][j]+mind[l][i]?dp[l][j-1]:dp[l][j]+mind[l][i];
					else
						tt = dp[l][j] + mind[l][i];	
					if(tt<min)
						min = tt;
				}
				dp[i][j] = min;
			}
		}
		printf("%d\n",dp[n][K]);
	}
	return 0;
}



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