【题解】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 ...
随机推荐
- aspnetcore 应用 接入Keycloak快速上手指南
登录及身份认证是现代web应用最基本的功能之一,对于企业内部的系统,多个系统往往希望有一套SSO服务对企业用户的登录及身份认证进行统一的管理,提升用户同时使用多个系统的体验,Keycloak正是为此种 ...
- 2020.12.20vj补题
A - Insomnia cure 题意:一共s只龙,每隔k,l,m,n只龙就会受伤,问这s只龙有多少龙是受伤的 思路:看起来题目范围并不是很多,直接进行循环判断 代码: 1 #include< ...
- JAVA 面试相关
1. int和Integer有什么区别? 答:Java是一个近乎纯洁的面向对象编程语言,但是为了编程的方便还是引入了基本数据类型,但是为了能够将这些基本数据类型当成对象操作,Java为每一个基本数据类 ...
- Excel导出数据Excel.Application组件权限设置方法
很多网络应用系统都会涉及到数据采用Excel方式导出的模块,部分朋友问我到底怎么弄,其实方式很多种,目前比较优秀的方式还是直接用Excel的Excel.Application方式比较合适. 采用Exc ...
- 持续集成和持续交付工具-jenkins
jenkins说明 jenkins是一款由Java编写的开源的持续集成工具,它运行在Servlet容器中(例如Apache Tomcat).它支持软件配置管理(SCM)工具(包括AccuRev SCM ...
- 搜狗拼音输入法v9.6a (9.6.0.3568) 去广告精简优化版本
https://yxnet.net/283.html 搜狗拼音输入法v9.6a (9.6.0.3568) 去广告精简优化版本 软件大小:29.2 MB 软件语言:简体中文 软件版本:去广告版 软件授权 ...
- Linux进阶之Jenkins持续集成介绍及安装演示
一.Jenkins介绍 Jenkins是一个开源软件项目,是基于Java开发的一种持续集成工具,用于监控持续重复的工作,旨在提供一个开放易用的软件平台,使软件的持续集成变成可能. Jenkins功能包 ...
- Linux进阶之环境变量文件/etc/profile、/etc/bashrc、/etc/environment
一.Centos 环境变量/etc/profile和/etc/profile.d 1.两个文件都是设置环境变量的文件. 2./etc/profile 是永久性的环境变量,是全局变量,/etc/prof ...
- TcaplusDB君 · 行业新闻汇编(5月25日)
TcaplusDB君一直密切关注着游戏行业和数据库行业的动态.以下是TcaplusDB君收集的近期的游戏行业和数据库行业的新闻,汇编整理,献给大家观看. (本篇文章部分内容来自网络) 第十一届中国数据 ...
- 【Web前端HTML5&CSS3】11-定位
笔记来源:尚硅谷Web前端HTML5&CSS3初学者零基础入门全套完整版 目录 定位的简介 1. 相对定位 偏移量(offset) 相对定位的特点 2. 绝对定位 绝对定位的特点 包含块(co ...