Looking for Order 压缩DP

来源:互联网 发布:ts文件合并 mac 编辑:程序博客网 时间:2024/06/04 18:20
C. Looking for Order
time limit per test
7.5 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 numbern (1 ≤ n ≤ 24) — the amount of objects the girl has. The followingn 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 ton), 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.

Sample test(s)
Input
0 021 1-1 1
Output
80 1 2 0 
Input
1 134 33 40 0
Output
320 1 2 0 3 0 

Codeforces (c) Copyright 2010-2014 Mike Mirz

思路: 用状态x: 转化为一串二进制数,位为1 的表示该物品一放回袋子中;dp[x] 维护物品放入袋子走的距离;

有三角形 二边之和大于第三边 ,不妨设 a+b > c 可以推出 a方+b方 + 2*a*b> c方;  所以 a方+b方 不一定大于 C方; 所以不存在贪心的捷径;一次拿俩个还是一次只拿一个只能根据实际物品位置确定;

同时,我们还可以发现,拿物品的先后顺序是没有影响的,先拿 (1,2) ,再拿(3,4),跟先拿(4,3)再拿(1,2)是没有本质区别的;所以我们在搜索时候就可以先找到一位为0的(即此位置i 为0 表示第I 物品尚未拿到包里),在去枚举另一个为0 的,即可进行下一步搜索,退出 i 的枚举~~

正如 (1,2)(3,4) 这个例子:

for(int i=0;i<n;i++) 
{

·    发现x的第i位 ==0 ;(假设为1物品)

    {

           for (枚举跟 i 一起拿的所有可能物品j ) 维护dp[x+(1<<i)+(1<<j)] 进一步搜;

                      (假设当前找的第一个是2物品)

             break ; 退出 i 的循环;

        如果没有这个break ,那么可能找到 i=3,然后j=4  把这个(3,4)状态丢进去继续搜,那下一次可能就((3,4),(1,2)) ;然而这个跟 ((1,2),(3,4))是一样的,大大浪费了时间!;

    }

}

同理,对一次只能拿一个物品的也一样的道理,因为没有拿的次序问题,所以只要找到状态 x 一个不为0 ,进行计算dp[y] ,进行下一步就可以了;

我用了queue,  从dp[0] 开始搜; 直到dp[1111……11] 结束;

#include<stdio.h>#include<string.h>#include<math.h>#include<string>#include<iostream>#include<algorithm>#include<vector>#include<queue>#include<list>#include<map>#include<set>using namespace std;struct node{    int x,y;    node(int x=0,int y=0):x(x),y(y){}    void init(){        scanf("%d%d",&x,&y);    }    node operator - (const node &a) const{        return node(x-a.x,y-a.y);    }};int dis2(node a){    return a.x*a.x+a.y*a.y;}const int N=24;node st,a[N+2];int n;int dist[N],pos[N][N];int dp[1<<N];bool vis[1<<N];node pre[1<<N];void deal_dist(){    for(int i=0;i<n;i++)        dist[i]=dis2(st-a[i]);    for(int i=0;i<n;i++)        for(int j=i+1;j<n;j++)            pos[i][j]=pos[j][i]=dis2(a[i]-a[j]);//    for(int i=0;i<n;i++)//        for(int j=0;j<n;j++)//         printf("pos [%d %d]=%d\n",i,j,pos[i][j]);}queue<int>que;void deal_min(int &a,int b){    if(a==-1) a=b;    else a=min(a,b);}void deal_dp(){    memset(dp,-1,sizeof(dp));    memset(vis,0,sizeof(vis));    dp[0]=0;    que.push(0);    int tp,y;    while(!que.empty()){     int x=que.front();que.pop();     vis[x]=0;     if(x==(1<<n)-1) break;     for(int i=0;i<n;i++){        if( ( (x>>i) & 1 ) == 0 ){            y=x+(1<<i);            tp=dp[y];            deal_min(dp[y],dp[x]+dist[i]*2);            if(tp!=dp[y]) pre[y]=node(x,i+1);            if(vis[y]==0){                que.push(y);                vis[y]=1;            }            for(int j=i+1;j<n;j++)               if( ( (x>>j) & 1 ) == 0 ){                y=x+(1<<i)+(1<<j);                tp=dp[y];                deal_min(dp[y],dp[x]+dist[i]+dist[j]+pos[i][j]);                if(tp!=dp[y]) pre[y]=node(x,(i+1)*100+(j+1));                if(vis[y]==0){                    que.push(y);                    vis[y]=1;                }               }            break;            }        }    }    tp=(1<<n)-1;    printf("%d\n",dp[tp]);    printf("0");    while(tp){        int id=pre[tp].y;        if(id>99){            printf(" %d %d 0",id/100,id%100);        }        else printf(" %d 0",id);       tp=pre[tp].x;    }    printf("\n");}int main(){//     freopen("in.in","r",stdin);     st.init();     scanf("%d",&n);     for(int i=0;i<n;i++) a[i].init();     deal_dist();     deal_dp();     return 0;}



0 0