题目描述 Description |
Once upon a time, there was a traveler.
|
输入描述 Input Description |
The input consists of multiple datasets, each in the following format. The last dataset is followed by a line containing five zeros (separated by a space). |
输出描述 Output Description |
For each dataset in the input, one line should be output as specified below. An output line should not contain extra characters such as spaces. |
样例输入 Sample Input |
3 4 3 1 4 3 1 2 1 2 10 2 3 30 3 4 20 2 4 4 2 1 3 1 2 3 3 1 3 3 4 1 2 4 2 5 2 4 3 4 1 5 5 1 2 10 2 3 10 3 4 10 1 2 0 1 2 1 8 5 10 1 5 2 7 1 8 4 5 6 3 1 2 5 2 3 4 3 4 7 4 5 3 1 3 25 2 4 23 3 5 22 1 4 45 2 5 51 1 5 99 0 0 0 0 0 |
样例输出 Sample Output |
30.000 3.667 Impossible Impossible 2.856 |
数据范围及提示 Data Size & Hint |
Since the number of digits after the decimal point is not specified, the above result is not the only solution. For example, the following result is also acceptable. 30.0 |
之前的一些废话:是时候准备会考了。。
题解:dp[S][i]表示当前已经用了S集合的车票,现在在i位置的最优解。四层循环暴力搞,第一层枚举S子集,第二层枚举i表示当前点,第三层枚举接下来使用哪张车票,第四层枚举要到哪个点,转移很显然。
代码:
#include<iostream> #include<algorithm> #include<cstdio> #include<queue> #include<cmath> #include<cstring> using namespace std; typedef long long LL; typedef pair<int,int> PII; #define mem(a,b) memset(a,b,sizeof(a)) inline int read() { int x=0,f=1;char c=getchar(); while(!isdigit(c)){if(c=='-')f=-1;c=getchar();} while(isdigit(c)){x=x*10+c-'0';c=getchar();} return x*f; } const int maxn=10,maxm=32; const double oo=2147483647.0; int n,m,p,s,t,ce=-1,a,b,c,all,horse[maxn],dis[maxm][maxm]; double dp[1<<maxn][maxm],ans=oo; int main() { while(scanf("%d%d%d%d%d",&n,&m,&p,&s,&t)!=EOF && (n || m || p || s ||t)) { mem(dis,-1);all=1<<n;ans=oo; for(int i=0;i<n;i++)horse[i]=read(); while(p--)a=read(),b=read(),c=read(),dis[a][b]=dis[b][a]=c; for(int i=0;i<all;i++)for(int j=1;j<=m;j++)dp[i][j]=oo; dp[0][s]=0.0; for(int i=0;i<all;i++) for(int j=0;j<n;j++)if(!(i&(1<<j))) for(int k=1;k<=m;k++) for(int l=1;l<=m;l++)if(dis[k][l]>=0) dp[i|(1<<j)][l]=min(dp[i|(1<<j)][l],dp[i][k]+(double)dis[k][l]/(double)horse[j]); for(int i=0;i<all;i++)ans=min(ans,dp[i][t]); if(ans==oo)printf("Impossible\n"); else printf("%lf\n",ans); } return 0; }
总结:状压DP中的循环顺序很重要,位运算优先级比较神奇,还是加上括号保险为好。