C. Looking for Order

题目链接:http://codeforces.com/problemset/problem/8/C

C. Looking for Order
time limit per test
4 seconds
memory limit per test
512 megabytes
input
standard input
output
standard output

Girl Lena likes it when everything is in order, and looks for order everywhere. Once she was getting ready for the University and noticed that the room was in a mess — all the objects from her handbag were thrown about the room. Of course, she wanted to put them back into her handbag. The problem is that the girl cannot carry more than two objects at a time, and cannot move the handbag. Also, if he has taken an object, she cannot put it anywhere except her handbag — her inherent sense of order does not let her do so.

You are given the coordinates of the handbag and the coordinates of the objects in some Сartesian coordinate system. It is known that the girl covers the distance between any two objects in the time equal to the squared length of the segment between the points of the objects. It is also known that initially the coordinates of the girl and the handbag are the same. You are asked to find such an order of actions, that the girl can put all the objects back into her handbag in a minimum time period.

Input

The first line of the input file contains the handbag's coordinates xs, ys. The second line contains number n (1 ≤ n ≤ 24) — the amount of objects the girl has. The following n lines contain the objects' coordinates. All the coordinates do not exceed 100 in absolute value. All the given positions are different. All the numbers are integer.

Output

In the first line output the only number — the minimum time the girl needs to put the objects into her handbag.

In the second line output the possible optimum way for Lena. Each object in the input is described by its index number (from 1 to n), the handbag's point is described by number 0. The path should start and end in the handbag's point. If there are several optimal paths, print any of them.

Examples
input
Copy
0 0
2
1 1
-1 1
output
Copy
8
0 1 2 0
input
Copy
1 1
3
4 3
3 4
0 0
output
Copy
32
0 1 2 0 3 0

题意:

一个平面上放着许多东西,每个东西都有一个坐标,最开始一个人在一个起始坐标,她出发去拿东西,一次要么拿一件东西,要么拿两件东西,拿了之后必须返回起始坐标。

每次花费的时间是两个坐标距离的平方,问拿完所有的东西需要的最少的时间。

思路:状压dp,考虑每次取一个或者两个的情况,但是代码中的break不是很懂

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<stack>
#include<map>
#include<queue>
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
#define sc1(a) scanf("%lld",&a)
#define pf1(a) printf("%lld
",a)
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
const LL INF=1e18;
const ull base=2333;
const int maxn=1e1+50;
const int maxm=1e2+50;
const int maxv=1e6+5;
const int mod=1e9+7;
const int ba=3e5;
struct Node
{
    LL x,y;
}a[maxn];
LL N;
LL dis[maxn][maxn];
LL dp[1<<24];//dp[s] 当前得到的集合为s 因为起点只能是1  得到一个或者两个 所以一维就够了
LL now[1<<24],last[1<<24];
vector<LL>ans;
void Init()
{
    for(int i=0;i<(1<<N);i++)
    {
        dp[i]=INF;
        now[i]=last[i]=-1;
    }
}
LL Cal_Node(Node xx,Node yy)
{
    return (xx.x-yy.x)*(xx.x-yy.x)+(xx.y-yy.y)*(xx.y-yy.y);
}
void Cal_dis()
{
    for(int i=0;i<=N;i++)
    {
        for(int j=0;j<=N;j++)
        {
            dis[i][j]=Cal_Node(a[i],a[j]);
        }
    }
}
void Solve()
{
    dp[0]=0;
    for(int s=0;s<(1<<N);s++)
    {
        for(int i=1;i<=N;i++)
        {
            if((s&(1<<(i-1)))==0)// s不包含i 选i
            {
                LL v=dis[0][i]*2;//并且回到手提包的位置 选一次
                //还得记录路径
                if(dp[s]+v<dp[s|(1<<(i-1))])
                {
                    dp[s|(1<<(i-1))]=dp[s]+v;
                    now[s|(1<<(i-1))]=i;//
                    last[s|(1<<(i-1))]=s;//从s过来
                }
                //选两次 再选一个j
                for(int j=i+1;j<=N;j++)
                {
                    if((s&(1<<(j-1)))==0) //选i和j
                    {
                        v=dis[0][i]+dis[i][j]+dis[j][0];
                        if(dp[s]+v<dp[s|(1<<(i-1))|(1<<(j-1))])
                        {
                            dp[s|(1<<(i-1))|(1<<(j-1))]=dp[s]+v;
                            last[s|(1<<(i-1))|(1<<(j-1))]=s;
                            now[s|(1<<(i-1))|(1<<(j-1))]=i*100+j;//存两位
                        }
//                        dp[s|(1<<(i-1))|(1<<(j-1))]=min(dp[s|(1<<(i-1))|(1<<(j-1))],dp[s]+v);
                    }
                }
                break;
            }
        }
    }
//    for(int i=0;i<(1<<N);i++) cout<<dp[i]<<" "<<endl;
}
void Print(LL x)
{
    if(x==0) return ;
    if(last[x]!=-1)
    {
        Print(last[x]);//一直递归到最开始
    }
    if(now[x]>100) ans.push_back(now[x]/100);
    ans.push_back(now[x]%100);
    ans.push_back(0);
}
int main()
{
    sc1(a[0].x);sc1(a[0].y);//手提包的坐标
    sc1(N);
    Init();
    for(int i=1;i<=N;i++)
    {
        sc1(a[i].x);sc1(a[i].y);
    }
    Cal_dis();
    Solve();
    pf1(dp[(1<<N)-1]);
    Print((1<<N)-1);
    printf("0");
    for(int i=0;i<ans.size();i++)
    {
        printf(" %d",ans[i]);
    }
    printf("
");
    return 0;
}
/**

*/
当初的梦想实现了吗,事到如今只好放弃吗~
原文地址:https://www.cnblogs.com/caijiaming/p/12317545.html