ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CF8C Looking for Order 题解

2021-11-05 21:31:23  阅读:145  来源: 互联网

标签:原点 int 题解 long Looking y1 CF8C include dp


题意:平面上有n个点,一开始在原点,每次从原点出发最多经过2个点就必须返回原点,问走完所有点的最小距离,和一种走法。\((n \leq 24)\)

考虑贪心,由于每个点到达原点的路都至少走一次,所以可以把这些边先加进去然后去掉,然后变成在n个点的完全图中选边使其成为二分图且总权值和最小,这时贪心显然没有正确性。

根据数据范围考虑状压dp,暴力转移复杂度不能接受,容易发现对于任意两次从原点出发,取点,返回原点的过程,将它们互换不会影响结果。从而只需要记录哪些点走了哪些点没走。开一个\(2^{24}\)大小的数组即可,另外为了存储路径,还要再开一个相同大小的数组,这样已经几乎卡满空间。

考虑如何保证不反复尝试同一走法的不同顺序,只需要在找到第一个可以转移的单次的两个取点的第一个点即可,这样保证了不会反复转移。

注意输出路径,开一个数组存放一种dp状态是又哪一种转移过来的。(为什么不能反过来存,感觉也有正确性,毕竟是最优子结构)。

接下来是简单转移,枚举i,j:

\[dp_{t|(1<<i-1|1<<j-1)}=dp_t+dis[0][i]+dis[0][j]+dis[i][j] \]

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <assert.h>
using namespace std;
const int N = 25;
const long long INF = 0x7ffffffff;
struct point
{
    long long x, y;
} p[N];
long long getdis(int a, int b)
{
    int x1 = p[a].x, x2 = p[b].x, y1 = p[a].y, y2 = p[b].y;
    return (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
}
int n;
int dis[N][N];
long long dp[(1 << N - 1) + 5], route[(1 << N - 1) + 5];
int main()
{
    ios::sync_with_stdio(false);
    cin >> p[0].x >> p[0].y;
    cin >> n;
    for (int i = 1; i <= n; i++)
        cin >> p[i].x >> p[i].y;
    for (int i = 0; i <= n; i++)
        for (int j = 0; j <= n; j++)
            dis[i][j] = getdis(i, j);
    for (int i = 1; i <= (1 << n) - 1; i++)
        dp[i] = INF;
    dp[0] = 0;
    for (int t = 0; t <= (1 << n) - 1; t++)
    {
        if (dp[t] == INF)
            continue;
        for (int i = 1; i <= n; i++)
        {
            if (t & (1 << i - 1))
                continue;
            for (int j = 1; j <= n; j++)
            {
                if (t & (1 << j - 1))
                    continue;
                if (dp[t] + dis[0][i] + dis[0][j] + dis[i][j] < dp[t | (1 << i - 1) | (1 << j - 1)])
                {
                    dp[t | (1 << i - 1) | (1 << j - 1)] = dp[t] + dis[0][i] + dis[0][j] + dis[i][j];
                    route[t | (1 << i - 1) | (1 << j - 1)] = t;
                }
            }
            break;
        }
    }
    cout << dp[(1 << n) - 1] << endl;
    for (int i = (1 << n) - 1; i; i = route[i])
    {
        cout << 0 << " ";
        int temp = route[i] ^ i;
        for (int j = 1; j <= n; j++)
            if (temp & (1 << j - 1))
                cout << j << " ";
    }
    cout << 0 << endl;
}

标签:原点,int,题解,long,Looking,y1,CF8C,include,dp
来源: https://www.cnblogs.com/KinuhataSaiai/p/15515300.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有