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; }