zoukankan      html  css  js  c++  java
  • Codeforces 8C 状压DP

    题意:有个人想收拾行李,而n个物品散落在房间的各个角落里(n < 24)。现在给你旅行箱的坐标(人初始在旅行箱处),以及n个物品的坐标,你一次只能拿最多两个物品,并且拿了物品就必须放回旅行箱,不能暂时放在地上。问最小的花费是多少?花费是笛卡尔距离的平方。

    思路一看n 只有24,应该很容易想到要用状压DP. 那么dp[i]表示i状态并且回到原点的最小花费。那么就暴力枚举拿1个或两个物品放回原点,然后转移就行了。需注意,这个题目中拿物品的顺序对答案无影响,比如先拿1号,再拿2号和先拿2号,再拿1号的花费是一样的。然后满怀欣喜的交了一发,TLE了。。。。我们对题目的性质发掘的不够,既然枚举的时候拿物品的顺序对答案没影响,那么我们状态转移的时候顺序改变对答案没影响。比如现在有1, 2, 3, 4这4个物品没有选,那么先选1, 2再选3,4和先选3,4再选1, 2答案是一样的。所以我们枚举的时候,找到与之前没选过的最靠前的一个,再找出与这个对应的其它状态去更新就可以了。

    代码:

    #include <bits/stdc++.h>
    #define pii pair<int, int>
    using namespace std;
    const int maxn = 30;
    int dis(pii x, pii y) {
    	return (x.first - y.first) * (x.first - y.first) + (x.second - y.second) * (x.second - y.second);
    }
    int dp[1 << 24], pre[1 << 24];
    pii s, a[maxn];
    int n;
    int cost[30][30];
    void print(int now) {
    	if(now == 0) {
    		printf("0 ");
    		return;
    	}
    	print(now ^ pre[now]);
    	for (int i = 0; i < n; i++) {
    		if((pre[now] >> i) & 1)
    			printf("%d ", i + 1);
    	}
    	printf("0 ");
    }
    int main() {
    	scanf("%d%d",&s.first, &s.second);
    	scanf("%d", &n);
    	for (int i = 0; i < n; i++) {
    		scanf("%d%d", &a[i].first, &a[i].second);
    	}
    	for (int i = 0; i < n; i++)
    		for (int j = 0; j < n; j++) {
    //			int now = (1 << i) | (1 << j);
    //			re.push_back(now);
    			int tmp1 = dis(s, a[i]);
    			if(i != j) {
    				tmp1 += dis(a[i], a[j]);
    				tmp1 += dis(a[j], s);
    			} else {
    				tmp1 += dis(a[i], s);
    			}
    			//dist.push_back(tmp1);
    			cost[i][j] = tmp1;
    		}
    	memset(dp, 0x3f, sizeof(dp));
    	dp[0] = 0;
    	for (int i = 0; i < (1 << n); i++) {
    		for (int j = 0; j < n; j++) {
    			if((i >> j) & 1) continue;
    			for (int k = j; k < n; k++){
    				if((i >> k) & 1) continue;
    				int now = (1 << j) | (1 << k);
    				if(dp[i | now] > dp[i] + cost[j][k]) {
    					dp[i | now] = min(dp[i | now], dp[i] + cost[j][k]);
    					pre[i | now] = now;
    				}
    			}
    			break;
    		}	
    	}
    	printf("%d
    ", dp[(1 << n) - 1]);
    	print((1 << n) - 1);
    }
    

      

  • 相关阅读:
    z-index坑
    一些常用的可以封装好的方法
    echarts线状图
    vue 用js复制内容
    Java并发系列
    ThreadLocal讲解
    TreeMap源码学习
    HashMap源码学习
    Java Socket编程
    socket、tcp、udp、http 的认识及区别
  • 原文地址:https://www.cnblogs.com/pkgunboat/p/10799563.html
Copyright © 2011-2022 走看看