【题解】codeforces 8c Looking for Order 状压dp
题目描述
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的更多相关文章
- codeforces 8C. Looking for Order 状压dp
题目链接 给n个物品的坐标, 和一个包裹的位置, 包裹不能移动. 每次最多可以拿两个物品, 然后将它们放到包里, 求将所有物品放到包里所需走的最小路程. 直接状压dp就好了. #include < ...
- 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 ...
- Codeforces Round #363 LRU(概率 状压DP)
状压DP: 先不考虑数量k, dp[i]表示状态为i的概率,状态转移方程为dp[i | (1 << j)] += dp[i],最后考虑k, 状态表示中1的数量为k的表示可行解. #incl ...
- Codeforces 429C Guess the Tree(状压DP+贪心)
吐槽:这道题真心坑...做了一整天,我太蒻了... 题意 构造一棵 $ n $ 个节点的树,要求满足以下条件: 每个非叶子节点至少包含2个儿子: 以节点 $ i $ 为根的子树中必须包含 $ c_i ...
- Codeforces 895C Square Subsets(状压DP 或 异或线性基)
题目链接 Square Subsets 这是白书原题啊 先考虑状压DP的做法 $2$到$70$总共$19$个质数,所以考虑状态压缩. 因为数据范围是$70$,那么我们统计出$2$到$70$的每个数的 ...
- Codeforces 895C Square Subsets:状压dp【组合数结论】
题目链接:http://codeforces.com/problemset/problem/895/C 题意: 给你n个数a[i].(n <= 10^5, 1 <= a[i] <= ...
- CodeForces 599E Sandy and Nuts 状压DP
题意: 有一棵\(n(1 \leq n \leq 13)\)个节点的树,节点的标号为\(1 \sim n\),它的根节点是\(1\). 现在已知它的\(m(0 \leq m < n)\)条边,和 ...
- codeforces 580D Kefa and Dishes(状压dp)
题意:给定n个菜,每个菜都有一个价值,给定k个规则,每个规则描述吃菜的顺序:i j w,按照先吃i接着吃j,可以多增加w的价值.问如果吃m个菜,最大价值是多大.其中n<=18 思路:一看n这么小 ...
- Codeforces 342D Xenia and Dominoes 状压dp
码就完事了. #include<bits/stdc++.h> #define LL long long #define fi first #define se second #define ...
随机推荐
- Postman报文进行解密之RSA私钥解密
接口返回的数据也是加密的,需要对数据解密才能看到返回的数据是否正确,就需要用RSA解密. 返回数据的解析可以在postman的Tests进行后置处理,获取加密后的返回数据: var data = JS ...
- 在Visual Studio 中使用git——文件管理-上(四)
在Visual Studio 中使用git--什么是Git(一) 在Visual Studio 中使用git--给Visual Studio安装 git插件(二) 在Visual Studio 中使用 ...
- Jenkins 基础篇 - 安装部署
Jenkins 安装 Jenkins 支持主流的 Linux 发行版系统,同时还支持 macOS.Windows.和 Docker 运行. 具体系统的 Jenkins 安装包可以去官网下载 https ...
- SQLFlow使用中的注意事项--设置篇
SQLFlow 是用于追溯数据血缘关系的工具,它自诞生以来以帮助成千上万的工程师即用户解决了困扰许久的数据血缘梳理工作. 数据库中视图(View)的数据来自表(Table)或其他视图,视图中字段(Co ...
- 2020 ICPC EC Final西安现场赛游记
也不知道从何说起,也不知道会说些什么,最想表达的就是很累很累. 从第一天去的时候满怀希望,没什么感觉甚至还有一些兴奋.到后来一直在赶路,感觉很疲惫,热身赛的时候觉得马马虎虎,导致热身赛被咕.然后教练就 ...
- Rabbit MQ一些参数解释
//ConnectionFactory(连接工厂): 生产Connection的的工厂 //Connection(连接):是RabbitMQ的socket的长链接,它封装了socket协议相关部分逻辑 ...
- [Java] HOW2J(Java初级)
变量 基本类型:整型(byte.short.int.long).字符型(char).浮点型(float.double).布尔型(boolean) 给基本类型赋值的方式叫字面值 字符的字面值放在单引号中 ...
- [转发]Linux性能测试工具之Lmbench特性、安装及使用
Linux性能测试工具之Lmbench特性.安装及使用2015年07月16日 10:13:48 Michaelwubo 阅读数:2466Linux性能测试工具Lmbench 是一套简易可移植的,符合A ...
- Linux中find命令用法全汇总,看完就没有不会用的!
Linux中find命令用法全汇总,看完就没有不会用的! 中琦2513 马哥Linux运维 2017-04-10 糖豆贴心提醒,本文阅读时间7分钟 Linux 查找命令是Linux系统中最重要和最 ...
- Java 中布尔(boolean)类型占用多少个字节
为什么要问这个问题,首先在Java中定义的八种基本数据类型中,除了其它七种类型都有明确的内存占用字节数外,就 boolean 类型没有给出具体的占用字节数,因为对虚拟机来说根本就不存在 boolean ...