CF1042B Vitamins:
题目描述
输入格式
输出格式
题意翻译
输入输出样例
输入 #1
4 5 C 6 B 16 BAC 4 A
输出 #1
15
输入 #2
2 10 AB 15 BA
输出 #2
-1
输入 #3
5 10 A 9 BC 11 CA 4 A 5 B
输出 #3
13
输入 #4
6 100 A 355 BCA 150 BC 160 AC 180 B 190 CA
输出 #4
250
输入 #5
2 5 BA 11 CB
输出 #5
16
析
看到奶酪的数据范围就可以想到状压dp,我们先预处理出任意两点之间的距离用dis数组保存,然后枚举状态,由于我们不知道此状态的上一个被吃的奶酪在什么位置,所以要加一维保存上一个奶酪的位置,状态转移方程为f[s][i]=min(f[s][i],f[s-(1<<(i-1))][k]+dis[k][i]);然后在枚举每一个吃最后一个吃的位置(f[maxn-1][i])找到最小的,输出就ok了
Code
#include<bits/stdc++.h> using namespace std; int n; double x[17],y[17];//注意浮点数 double f[1<<17][17]; double dis[17][17]; double sui(double x1,double y1,double x2,double y2){//求两点之间的距离 return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); } int main(){ scanf("%d",&n); int maxn=1<<n; for(int i=1;i<=n;i++){ scanf("%lf%lf",&x[i],&y[i]); dis[0][i]=dis[i][0]=sui(0.0,0.0,x[i],y[i]);//起点到一点的距离 } for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ dis[i][j]=sui(x[i],y[i],x[j],y[j]);//任意两点的距离 } } for(int i=0;i<maxn;i++){ for(int j=1;j<=n;j++){ f[i][j]=1e9;//初始化最大值 } } for(int i=1;i<=n;i++){//只吃一个的各个路程 f[1<<(i-1)][i]=dis[0][i]; } f[0][0]=0; for(int s=0;s<maxn;s++){ for(int i=1;i<=n;i++){ if(!(s&(1<<(i-1))))continue;//i没有吃,直接跳过 for(int k=1;k<=n;k++){ if(k==i||!(s&(1<<(k-1))))continue;//k(上一个点)没吃,或者k等于i(此点),跳过 f[s][i]=min(f[s][i],f[s-(1<<(i-1))][k]+dis[k][i]); } } } double ans=1e9; for(int i=1;i<=n;i++){//找最小 ans=min(ans,f[maxn-1][i]); } printf("%.2lf",ans); return 0; }