题目描述

Lena喜欢秩序井然的生活。一天,她要去上大学了。突然,她发现整个房间乱糟糟的——她的手提包里的物品都散落在了地上。她想把所有的物品都放回她的手提包。但是,这里有一点问题:她一次最多只能拿两个物品,她也不能移动她的手提包。并且,因为她爱整洁的习惯,如果她拿起了一个物品,她也不能将它放在其他地方,除非放回她的手提包。

Lena把她的房间划分为了一个平面直角坐标系。现在Lena给你她的手提包和每个散落的物品的坐标(当然,一开始的时候她就和手提包站在一个地方)。她从坐标 $(x1,y1)$ 走到坐标 $(x2,y2)$ 需要用 $(x1-x2)^{2}+(y1-y2)^{2}$ 单位的时间。现在,Lena将告诉你她的房间的情况,请你为Lena找到一个拾起每个物品的顺序,使她拾起所有物品所需的总时间最小。当然,Lena最后需要返回她的手提包。

输入输出格式

输入格式

输入文件的第一行为Lena的手提包的坐标 $x_{s}​$ , $y_{s}$​ 。第二行为一个正整数 n ,表示总的需要拾起的物品数。接下来的 n 行每行包括两个整数,表示每个物品的坐标。

输出格式

输出的第一行为一个正整数,表示Lena拾起所有物品所需的最小时间。

输出的第二行为Lena拾起每个物品的顺序。(每一个物品由它的编号代表,0表示手提包)她应该从手提包(0)出发,在手提包(0)结束。

如,0 1 2 0 3 0

表示她从手提包出发,先拾起1号物品,再拾起2号物品,然后返回手提包(并放下1和2),再拾起3号物品,最后返回手提包。

如果有多条允许的路径,输出任一条。

输入输出样例

输入样例#1:

0 0
2
1 1
-1 1

输出样例#1:

0 0
8
0 1 2 0

输入样例#2:

0 0
1 1
3
4 3
3 4
0 0

输出样例#2:

0 0
32
0 1 2 0 3 0

思路

状压DP

以当前已经取了哪些物品作为状态。

$n<=24$ 的数据范围和512MB的空间限制基本上就标志着这道题是一个标准的状压。

为了节省空间,我们就用 $1<<i-1$ 表示第 i 个物品有无被取过。由于一次可以选择拿一个或者两个物品,考虑在状态转移的时候枚举这次拿的两个物品(如果两个物品相同就处理为这次只拿一个)。

由于要输出拿的方法,我们就再用一个数组记录当前状态是从之前的哪个状态转移过来的即可。

需要注意的是,可以证明,若设每次离开手提包捡拾物品为一次,则各次之间的顺序不影响最终答案。

如,第一次拿物品1,第二次拿物品2,3与第一次拿物品2,3,第二次拿物品1的所用时间是一样的。这样,我们在转移的时候就从编号小的物品向编号大的物品找寻,只要找到了当前的一种可用方案就可以进入下一个状态了,这样可以节省时间(同时避免重复计算)。

代码

#include<cmath>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#define re register int
using namespace std;
const int MAXN=24, INF=2e9;
struct obj
{
int x, y;
} things[MAXN+1];
int n;
int dp[1<<MAXN|1], pre[1<<MAXN|1];
int dis[MAXN+1][MAXN+1];
inline int min( int a, int b ) { return a<b?a:b; }
inline int read(){
int x=0,w=1;
char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') w=-1,ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+ch-48,ch=getchar();
return x*w;
}
inline void solve();
int main( )
{
for(re i=0;i<=(1<<MAXN);++i) dp[i]=INF,pre[i]=0;
things[0].x=read();
things[0].y=read();
n=read();
for(re i=1;i<=n;++i) things[i].x=read(),things[i].y=read();
for(re i=0;i<=n;++i) for(re j=0;j<=n;++j)
{
dis[i][j]=dis[j][i]=
(things[i].x-things[j].x)*(things[i].x-things[j].x)+
(things[i].y-things[j].y)*(things[i].y-things[j].y);
}
solve();
printf("%d\n",dp[(1<<n)-1]);
int now=(1<<n)-1; //从全部拿完的状态开始往前推
while (now!=0)
{
printf("0 ");
int update=now^pre[now];
for(int i=1;i<=n;i++) if(update&1<<i-1) printf("%d ",i);
now=pre[now];
}
printf("0\n");
return 0;
} inline void solve( )
{
dp[0]=0,pre[0]=0;
for(int m=0;m<(1<<n);m++)
{
if(dp[m]==INF) continue; //如果当前状态没有被更新过直接continue
for(int i=1;i<=n;i++)
{
if(m&1<<i-1) continue; //如果已经拿过了
for(int j=1;j<=n;j++)
{
if(m&1<<j-1) continue;
if(dp[m|(1<<i-1)|(1<<j-1)]>dp[m]+dis[0][i]+dis[i][j]+dis[j][0])
{
dp[m|(1<<i-1)|(1<<j-1)]=dp[m]+dis[0][i]+dis[i][j]+dis[j][0];
pre[m|(1<<i-1)|(1<<j-1)]=m; //状态转移
}
}
break;
}
}
return;
}

转自星烁晶熠辉

【题解】codeforces 8c Looking for Order 状压dp的更多相关文章

  1. codeforces 8C. Looking for Order 状压dp

    题目链接 给n个物品的坐标, 和一个包裹的位置, 包裹不能移动. 每次最多可以拿两个物品, 然后将它们放到包里, 求将所有物品放到包里所需走的最小路程. 直接状压dp就好了. #include < ...

  2. Codeforces Beta Round #8 C. Looking for Order 状压dp

    题目链接: http://codeforces.com/problemset/problem/8/C C. Looking for Order time limit per test:4 second ...

  3. Codeforces Round #363 LRU(概率 状压DP)

    状压DP: 先不考虑数量k, dp[i]表示状态为i的概率,状态转移方程为dp[i | (1 << j)] += dp[i],最后考虑k, 状态表示中1的数量为k的表示可行解. #incl ...

  4. Codeforces 429C Guess the Tree(状压DP+贪心)

    吐槽:这道题真心坑...做了一整天,我太蒻了... 题意 构造一棵 $ n $ 个节点的树,要求满足以下条件: 每个非叶子节点至少包含2个儿子: 以节点 $ i $ 为根的子树中必须包含 $ c_i ...

  5. Codeforces 895C Square Subsets(状压DP 或 异或线性基)

    题目链接  Square Subsets 这是白书原题啊 先考虑状压DP的做法 $2$到$70$总共$19$个质数,所以考虑状态压缩. 因为数据范围是$70$,那么我们统计出$2$到$70$的每个数的 ...

  6. Codeforces 895C Square Subsets:状压dp【组合数结论】

    题目链接:http://codeforces.com/problemset/problem/895/C 题意: 给你n个数a[i].(n <= 10^5, 1 <= a[i] <= ...

  7. CodeForces 599E Sandy and Nuts 状压DP

    题意: 有一棵\(n(1 \leq n \leq 13)\)个节点的树,节点的标号为\(1 \sim n\),它的根节点是\(1\). 现在已知它的\(m(0 \leq m < n)\)条边,和 ...

  8. codeforces 580D Kefa and Dishes(状压dp)

    题意:给定n个菜,每个菜都有一个价值,给定k个规则,每个规则描述吃菜的顺序:i j w,按照先吃i接着吃j,可以多增加w的价值.问如果吃m个菜,最大价值是多大.其中n<=18 思路:一看n这么小 ...

  9. Codeforces 342D Xenia and Dominoes 状压dp

    码就完事了. #include<bits/stdc++.h> #define LL long long #define fi first #define se second #define ...

随机推荐

  1. Vulnerability: Cross Site Request Forgery (CSRF)

    CSRF跨站请求伪造 这是一种网络攻击方式,也被称为one-click attack或者session riding 攻击原理 CSRF攻击利用网站对于用户网页浏览器的信任,挟持用户当前已登陆的Web ...

  2. Dart 2.13 版现已发布

    作者 / Kevin Moore & Michael Thomsen Dart 2.13 版现已发布,其中新增了类型别名功能,这是目前用户呼声第二高的语言功能.Dart 2.13 还改进了 D ...

  3. CentOS 7 设置日期和时间 timedatectl

    CentOS 7 设置日期和时间 在CentOS 6版本,时间设置有date.hwclock命令,从CentOS 7开始,使用了一个新的命令timedatectl. timedatectl [root ...

  4. Docker——Jenkins + Git + Registry构建自动化持续集成环境(CI/CD)

    前言 在互联网时代,对于每一家公司,软件开发和发布的重要性不言而喻,目前已经形成一套标准的流程,最重要的组成部分就是持续集成(CI)及持续部署.交付(CD). 本文基于Jenkins+Docker+G ...

  5. Linux上使用iSCSI概述

    iSCSI简介 1. scsi和iscsi SCSI技术是存储设备最基本的标准协议,通常需要设备互相靠近并用SCSI总线连接,因此受到物理环境的限制 iSCSI(Internet Small Comp ...

  6. HAProxy与LVS综合----搭建LNMP源码编译结合HAProxy或LVS负载均衡

    实战一:实现LNMP与Keepalived.HAProxy做反向代理 框架图: 实现原理: 1.当A用户访问网站时,此时需要经过防火墙,防火墙将用户访问的IP地址处理后,如果允许访问,则就访问到HAr ...

  7. 使用Wok管理kvm虚拟机

    [Centos7.4] !!!测试环境我们首关闭防火墙和selinux [root@localhost ~]# systemctl stop firewalld [root@localhost ~]# ...

  8. 云计算OpenStack核心组件---neutron网络服务(8)*****

    一.neutron介绍 1.Neutron概述 传统的网络管理方式很大程度上依赖于管理员手工配置和维护各种网络硬件设备:而云环境下的网络已经变得非常复杂,特别是在多租户场景里,用户随时都可能需要创建. ...

  9. shell基础之case应用

    在server0上穿件一个名为/root/script.sh的脚本,让其提供给下列的特性    1.当运行/root/script.sh all,输出为none 2.当运行/root/script.s ...

  10. java面试一日一题:java中的垃圾回收器

    问题:请讲下java中垃圾回收器有哪些? 分析:该问题主要考察hotspot虚拟机下实现的垃圾回收器 回答要点: 主要从以下几点去考虑, 1.垃圾回收器的种类 2.每种垃圾回收器的着重点是什么 前边的 ...