P1433 吃奶酪-状压dp
P1433 吃奶酪-状压dp
这是5.15晚自习的题目预习
直接上题逝一逝吧
放心,是对的代码
P1433 吃奶酪 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
记录详情 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
我真喜欢记忆化搜索(嘿嘿嘿)
记忆化搜索的话,更容易理解
dp[x] [zt]设定为走到点x时,状态为zt
而显然zt之和(“选/没选”)两种情况有关,所以设置一个二进制数,i-1位为1说明i选过了,为0则说明没选择
先考虑下最终状态,由于不知道最后是以哪个点结尾的,所以要用n的时间来枚举最后一个点是什么,而zt嘛,肯定是最后所有的都被选择了的,所以就是11111111….(n-1个1),而为了写的简便一些就是(1<<n)-1
考虑下转移,首先他肯定是从某个吃完了的地方(假如说是i,那么就是i-1=1的地方)转移过来,毕竟我从这个点i来都来了,这个点i上肯定吃了最好,而转移过来的状态我设置为zt1,显然就是把当前位置(x-1)的位置设为0(因为状态设置的是在x点时的状态,在x点时这个点肯定是被吃过的,为1,那么从他转移过来的点i肯定还没有吃x点上的,那么两者的状态就缺了个‘0’),这个可以用减法实现
最后想想末位状态,初始化即可
代码如下
#include<bits/stdc++.h>
using namespace std;
struct node{
double x;
double y;
}a[20];
double dis(double x,double y,double xx,double yy){
return sqrt((x-xx)*(x-xx)+(y-yy)*(y-yy));
}
int n;
double dp[20][1<<16];
double dfs(int x,int zt){//在x点时的状态
if(dp[x][zt]!=999999){
return dp[x][zt];
}
int zt1=zt-(1<<(x-1));
for(int i=1;i<=n;i++){//枚举转移到zt的点,且状态位置为1的点
if((zt1>>(i-1))&1==1){//这一位上是1
dp[x][zt]=min(dp[x][zt],dfs(i,zt1)+dis(a[x].x,a[x].y,a[i].x,a[i].y));
}
}
return dp[x][zt];
}
int main(){
ios::sync_with_stdio(false);
cin >> n;
a[0].x=0;
a[0].y=0;
for(int i=1;i<=n;i++){
cin >> a[i].x>>a[i].y;
}
//cout<<(1<<16);
for(int i=0;i<=n;i++){
for(int j=0;j<=(1<<n);j++){
dp[i][j]=999999;
//cout<<dp[i][j]<<endl;
}
}
//cout<<dp[1][15];
for(int i=1;i<=n;i++){
dp[i][1<<(i-1)]=dis(a[0].x,a[0].y,a[i].x,a[i].y);
}
double ans=9999999;
for(int i=1;i<=n;i++){
ans=min(ans,dfs(i,(1<<(n))-1));
}
printf("%.2f",ans);
}

浙公网安备 33010602011771号