Aizu - 2200 AOJ floyd+dp

题意:

你是某个岛国(ACM-ICPC Japan)上的一个苦逼程序员,你有一个当邮递员的好基友利腾桑遇到麻烦了:全岛有一些镇子通过水路和旱路相连,走水路必须要用船,在X处下船了船就停在X处。而且岛上只有一条船,下次想走水路还是得回到X处才行;两个镇子之间可能有两条以上的水路或旱路;邮递员必须按照清单上的镇子顺序送快递(镇子可能重复,并且对于重复的镇子不允许一次性处理,比如ABCB的话B一定要按顺序走两次才行)。

测试数据有多组:

N M

x1 y1 t1 sl1

x2 y2 t2 sl2

xM yM tM slM

R

z1 z2 … zR

N (2 ≤ N ≤ 200) 是镇子的数量,M (1 ≤ M ≤ 10000) 是旱路和水路合计的数量。从第2行到第M + 1行是路径的描述,路径连接xi yi两地,路径花费 ti (1 ≤ ti ≤ 1000)时间,sli 为L时表示是旱路,S时表示是水路。可能有两条及以上路径连接两个镇子,并且路径都是双向的。

M + 2行的R是利腾需要去的镇子的数量,M + 3行的z序列是利腾需要去的镇子的编号。

扫描二维码关注公众号,回复: 60513 查看本文章

初始状态利腾和船都在第一个镇子,且肯定有方法达到需要去的镇子。

测试数据为0 0的时候表示终止。

求这个人跑完Z序列所需的最短时间

来源:https://blog.csdn.net/yopilipala/article/details/79654036

思路:由于要求跑完整个z序列所需的最短时间,我们必须要预处理出陆路,水路所有点对之间的最短路,于是可以将陆路,水路分别建图,floyd跑一遍求得。

之后跑完z序列需要R步,每步的状态与上一步的位置和船的位置有关,并且具有递推关系,于是我们可以进行DP。(细节都在代码里了)。最终求得所有走到第R步时,船停在某点(1-n点)时的最短时间。从这n个里选出最小,即为答案。

#include<bits/stdc++.h>
#define sd(x) scanf("%d",&x)
#define ss(x) scanf("%s",x)
#define sc(x) scanf("%c",&x)
#define sf(x) scanf("%f",&x)
#define slf(x) scanf("%lf",&x)
#define slld(x) scanf("%lld",&x)
#define me(x,b) memset(x,b,sizeof(x))
#define pd(d) printf("%d\n",d);
#define plld(d) printf("%lld\n",d);
#define eps 1.0E-8
// #define Reast1nPeace

typedef long long ll;

using namespace std;

const int INF = 0x3f3f3f3f;
const ll LINF = 0x1f1f1f1f1f1f1f1f;

int n,m,r;
int land[210][210];
int water[210][210];
ll dp[1010][210];
int z[1010];

void floyd(){
	for(int i =1 ; i<=n ; i++){
		land[i][i] = water[i][i] = 0;
	}
	for(int k = 1 ; k<=n ; k++){
		for(int i = 1 ; i<=n ; i++){
			for(int j = 1 ; j<=n ; j++){
				if(land[i][j] > land[i][k]+land[k][j]){
					land[i][j] = land[i][k]+land[k][j];
				}
				if(water[i][j] > water[i][k]+water[k][j]){
					water[i][j] = water[i][k]+water[k][j];
				}
			}
		}
	} 
}

int main(){
#ifdef Reast1nPeace
	freopen("in.txt", "r", stdin);
	freopen("out.txt", "w", stdout);
#endif
	ios::sync_with_stdio(false);
	while(cin>>n>>m){
		if(n==0 && m==0) break;
		
		memset(land,INF,sizeof(land));
		memset(water,INF,sizeof(water));
		memset(dp,LINF,sizeof(dp));
		
		int x,y,t;string sl;
		for(int i = 1 ; i<=m ; i++){
			cin>>x>>y>>t>>sl;
			if(sl[0] == 'L'){
				land[x][y] = land[y][x] = min(land[x][y] , t);
			} 
			else{
				water[x][y] = water[y][x] = min(water[x][y] , t);
			}
		}
		cin>>r;
		for(int i = 1 ; i<=r ; i++){
			cin>>z[i];
		}
		floyd();
		
		//dp[i][j]表示走到z数组序列的第i步,船停在j点时走过的最短距离		
		dp[1][z[1]] = 0;
		for(int i = 1 ; i<=r ; i++){  //i是z数组的序号 
			for(int j = 1 ; j<=n ; j++){  //j表示船停在j号点 
				dp[i][j] = min(dp[i][j] , dp[i-1][j]+land[z[i-1]][z[i]]);  //只走陆地 
				for(int k = 1 ; k<=n ; k++){   //走水路的情况,船最终有n个位置可以停靠 
					dp[i][k] = min(dp[i][k] , dp[i-1][j]+land[z[i-1]][j]+water[j][k]+land[k][z[i]]);
					//走到第i步时,走水路,船最终停在k号点, 
					//从i-1步先走到船在的j点号,然后开船到k号点,再从陆路k到第i步的点。 
				}
			}
		}
		
		ll minn = LINF;
		for(int i = 1 ; i<=n ; i++){
			if(minn > dp[r][i]){
				minn = dp[r][i];
			}
		} 
		cout<<minn<<endl;
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Reast1nPeace/article/details/80071207