zoukankan      html  css  js  c++  java
  • 状压dp Codeforces Beta Round #8 C

    http://codeforces.com/contest/8/problem/C

    题目大意:给你一个坐标系,给你一个人的目前的坐标(该坐标也是垃圾桶的坐标),再给你n个垃圾的坐标,这个人要捡完所有的垃圾,而且每次最多只能捡两个,然后把他扔到垃圾桶里面去。问这个人捡完所有垃圾所需要的最短的路程是多少?(路程=两个坐标之间连线距离的平方)

    思路:貌似是简单的状压dp?

    我们枚举一下1<<n就好了,然后每次都取最高位和其他的某一个进行匹配即可(而不用取其他位,因为其他位在之前就已经枚举过了)。

    //看看会不会爆int!数组会不会少了一维!
    //取物问题一定要小心先手胜利的条件
    #include <bits/stdc++.h>
    using namespace std;
    #define LL long long
    #define ALL(a) a.begin(), a.end()
    #define pb push_back
    #define mk make_pair
    #define fi first
    #define se second
    #define haha printf("haha
    ")
    const int maxn = 24;
    int dp[1 << maxn], par[1 << maxn];
    pair<int, int> girl, a[maxn + 5];
    int n;
    
    inline int get_high(int val){///1需要右移几位
        int pos = 0;
        while (val){
            val >>= 1; pos++;
        }
        return pos - 1;
    }
    
    inline int dis(int x, int y){
        if (x == -1)
            return (girl.fi - a[y].fi) * (girl.fi - a[y].fi) + (girl.se - a[y].se) * (girl.se - a[y].se);
        return (a[x].fi - a[y].fi) * (a[x].fi - a[y].fi) + (a[x].se - a[y].se) * (a[x].se - a[y].se);
    }
    
    int main(){
        ///int high = get_high(4); pos = 2   4 = 100
        scanf("%d%d", &girl.fi, &girl.se);
        cin >> n;
        for (int i = 0; i < n; i++){
            int x, y; scanf("%d%d", &x, &y);
            a[i] = mk(x, y);
        }
        memset(dp, 0x3f, sizeof(dp));
        memset(par, -1, sizeof(par));
        dp[0] = 0;
        for (int i = 1; i < (1 << n); i++){
            int high = get_high(i);///最高位是第几位
            dp[i] = min(dp[i], dp[i ^ (1 << high)] + dis(-1, high) * 2);
            par[i] = i ^ (1 << high);
            for (int j = 0; j < high; j++){
                if (i & (1 << j)) {
                    int tmp = dp[i ^ (1 << j) ^ (1 << high)] + dis(j, high) + dis(-1, j) + dis(-1, high);
                    if (dp[i] > tmp){
                        dp[i] = tmp; par[i] = i ^ (1 << j) ^ (1 << high);
                    }
                }
            }
        }
        printf("%d
    ", dp[(1 << n) - 1]);
        int tmp = (1 << n) - 1;
        printf("0 ");
        for (int i = par[tmp]; i != -1; i = par[i]){
            int val = tmp ^ i;
            int pos = 0;
            while (val){
                if (val & 1) printf("%d ", pos + 1);
                val >>= 1; pos++;
            }
            printf("0 ");
            tmp = i;
        }
        cout << endl;
        return 0;
    }
    View Code
  • 相关阅读:
    标签的讲解
    属性分类
    LeetCode 003. 无重复字符的最长子串 双指针
    Leetcode 136. 只出现一次的数字 异或性质
    Leetcode 231. 2的幂 数学
    LeetCode 21. 合并两个有序链表
    象棋博弈资源
    acwing 343. 排序 topsort floyd 传播闭包
    Leetcode 945 使数组唯一的最小增量 贪心
    Leetcode 785 判断二分图 BFS 二分染色
  • 原文地址:https://www.cnblogs.com/heimao5027/p/5990854.html
Copyright © 2011-2022 走看看