P8733 [蓝桥杯 2020 国 C] 补给
看到数据范围 很小,考虑状压。
既然是状压,就考虑选了一个集合 会怎么样,不难发现,这里可以考虑选择走过的点当作集合,那么把走过的点对应的位置标记成 ,就能把它抽象成一个数了。
发现只有 还不够,设 表示集合 ,走到的最后一个点是 的最小路程,这里的起点是 。
转移的话就直接考虑枚举还没有走过的点(也就是集合内标记为 的点),对他们进行更新,发现我们需要求出 到 的最短距离。
题目中限制了单次路程不能超过 ,转换成两个点的距离不能超过 ,可以每飞两个点就加一次油。找到这些边(因为能使用的边只有这些),然后跑最短路,就可以知道在限制下两个点的最短路。
答案就是枚举最后一个点的可能,加上他到第一个点的最短距离就是答案。
#include<bits/stdc++.h>
using namespace std;
const int N =21;
double dp[(1<<20)+1][N],dis[N][N],ans=LONG_LONG_MAX,D;
struct node{
int x,y;
}a[N];
int n;
double Dis(int i,int j){
return sqrt((a[i].x-a[j].x)*(a[i].x-a[j].x)+(a[i].y-a[j].y)*(a[i].y-a[j].y));
}
void Floyd(){
for(int i=0;i<n;i++)
for(int j=0;j<n;j++){
dis[i][j]=1e21;
if(i==j) dis[i][j]=0.0;
else if(Dis(i,j)<=D) dis[i][j]=Dis(i,j);
}
for(int k=0;k<n;k++)
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(i!=k&&j!=k&&i!=j)
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
int main()
{
cin>>n>>D;
for(int i=0;i<n;i++) cin>>a[i].x>>a[i].y;
Floyd();
for(int i=0;i<(1<<n);i++)
for(int j=0;j<n;j++)
dp[i][j]=1e21;
dp[1][0]=0.0;
for(int i=0;i<(1<<n);i++){
if(i&1==0) continue;
for(int j=0;j<n;j++){
if((i>>j)&1==0) continue;
for(int k=0;k<n;k++){
if(i>>k&1==1) continue;
dp[i|(1<<k)][k]=min(dp[i|(1<<k)][k],dp[i][j]+dis[j][k]);
}
}
}
for(int i=1;i<n;i++)
ans=min(ans,dp[(1<<n)-1][i]+dis[i][0]);
cout<<fixed<<setprecision(2)<<ans<<endl;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现