题意:给出N个空瓶的坐标,模拟一个收瓶子机器人,他们都在一张桌子上,机器人一开始在其初始位置,每次其需要抓取一个空瓶,放到桌子外(走到边缘),然后继续抓取下一个空瓶(只能抓一个),问把所有瓶子处理掉时,机器人走过的最小距离和(double型)。
范围:N<=18,桌子的长宽<=1000
解法:状压DP,设DP[I][J] ,i 代表此时的状态(即走过的点集),至多为2的18次,J代表在 i 状态下最后一个点为 j :
故而转移方程为 DP[ new_state ][ new_pos ]= MIN{ DP[ state ][ pos ] +DIS[ pos ][ new_pos ] };
其中,DIS[i][j] 数组表示从i点到j 经过一次桌面边缘的最小距离。
初始时,将DP数组赋值为无穷大,其中,单独一个点的集合 的 dp值 取为 初始点到这个点的距离。
最终答案即:MIN { DP [ (1<<N ) - 1 ] [J] + J点到桌面边缘的最小距离 }
代码:
#include<stdio.h>
#include<math.h>
#include<iostream>
#include<algorithm>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
int W,H;
double dis[22][22];
double dp[540000][22];
struct node{
int x,y;
}a[22];
int n;
double cal(int i,int j){
int x=a[i].x;
int y=a[i].y;
int nx,ny;
double ans=200000000000000.0;
nx=-a[j].x;
ny=a[j].y;
ans=min(ans,sqrt((nx-x)*(nx-x)+(ny-y)*(ny-y)));
nx=a[j].x;
ny=-a[j].y;
ans=min(ans,sqrt((nx-x)*(nx-x)+(ny-y)*(ny-y)));
nx=W+W-a[j].x;
ny=a[j].y;
ans=min(ans,sqrt((nx-x)*(nx-x)+(ny-y)*(ny-y)));
nx=a[j].x;
ny=H+H-a[j].y;
ans=min(ans,sqrt((nx-x)*(nx-x)+(ny-y)*(ny-y)));
return ans;
}
double cald(int p){
int x=a[p].x;
int y=a[p].y;
double ans=200000000000000.0;
ans=min(ans,double(min(x,y)));
ans=min(ans,double(min(W-x,H-y)));
return ans;
}
main(){
FILE * f1 =fopen("kitchen.in","r");
FILE * f2 =fopen("kitchen.out","w");
while(fscanf(f1,"%d%d",&W,&H)!=EOF){
fscanf(f1,"%d",&n);
rep(i,1,n){
fscanf(f1,"%d%d",&a[i].x,&a[i].y);
}
int sx,sy;
fscanf(f1,"%d%d",&sx,&sy);
rep(i,1,n){
dis[i][i]=200000000000000.0;
rep(j,i+1,n){
dis[i][j]=dis[j][i]=cal(i,j);
//printf("dis[%d][%d]=%lf\n",i,j,dis[i][j]);
}
}
int tot=(1<<n)-1;
rep(i,0,tot)rep(j,1,n)dp[i][j]=200000000000000.0;
rep(i,1,n)dp[1<<(i-1)][i]=sqrt((a[i].x-sx)*(a[i].x-sx)+(a[i].y-sy)*(a[i].y-sy));
rep(st,1,tot){
rep(p,1,n){
if(~st&(1<<(p-1)))continue;
rep(np,1,n){
if(p==np)continue;
if(st&(1<<(np-1)))continue;
int nst=st|(1<<(np-1));
dp[nst][np]=min(dp[nst][np],dp[st][p]+dis[np][p]);
}
//printf("dp[%d][%d] = %.10lf\n",st,p,dp[st][p]);
}
}
double ans=200000000000000.0;
rep(i,1,n){
int st=tot;
ans=min(ans,dp[st][i]+cald(i));
}
fprintf(f2,"%.15lf\n",ans);
}
}