POJ2686(状压)

描述:
\(m个城市有p条双向道路。道路的花费是道路的距离/票上的数字。给出n张票,求a->b的最短路\)

开始本来想老套路把城市状态来压缩,但城市最多可以有30个,故考虑把船票压缩。

定义\(dp[i][j]\)为用的船票状态为i此时到达j城市的最短路

初始化为dp[0][a]=0,正常转移即可

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
int n,m,p,a,b;
double d[39][39],v[39],dp[1<<9][39];
int main()
{
	while(cin>>n>>m>>p>>a>>b&&(n+m))
	{
		a--,b--;
		double ans=1e18;
		for(int i=0;i<=30;i++)for(int j=0;j<=30;j++)d[i][j]=9999999999999;
		for(int i=0;i<n;i++)	cin>>v[i];
		for(int i=0;i<p;i++)
		{
			int l,r;double w;
			cin>>l>>r>>w;l--,r--;
			d[l][r]=d[r][l]=w;
		}
		for(int i=0;i<(1<<9);i++)for(int j=0;j<=m;j++)dp[i][j]=99999999999;
		dp[0][a]=0;
		int len=(1<<n);
		for(int i=0;i<len;i++)
		{
			for(int j=0;j<n;j++)
			{
				if(i&(1<<j))//这次用哪张票 
				{
					for(int q=0;q<m;q++)//当前在q城市
					{
						for(int k=0;k<m;k++)//从k城市转移而来 
						{
							if(q==k)	continue;	
						//	dp[i][q]=min(dp[i][q],dp[i-(1<<j)][k]+d[q][k]/v[j]);
							dp[i][k]=min(dp[i][k],dp[i-(1<<j)][q]+d[q][k]/v[j]);
							if(k==b)	
								ans=min(ans,dp[i][k]);
						}	
					} 
				}
			}
		}
		if(ans>=99999999998)	cout<<"Impossible"<<endl;
		else printf("%.3lf\n",ans);
	}
}
posted @ 2020-04-01 13:59  倾叶子佮  阅读(126)  评论(1编辑  收藏  举报