BNUOJ 弱校联萌15-16第三次训练赛同步赛 K题 Kitchen Robot [状压DP]

本文介绍了一种使用状态压缩动态规划(状压DP)解决空瓶收集问题的方法,目标是最小化机器人处理所有空瓶时行走的总距离。详细解释了状态转移方程和DP数组初始化,并提供了代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:给出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);
    }


}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值