原題:
You have been given the job of forming the quiz teams for the next ‘MCA CPCI Quiz Championship’.
There are 2∗N students interested to participate and you have to form N teams, each team consisting of two members. Since the members have to practice together, all the students want their members house as near as possible. Let x1be the distance between the houses of group 1, x2be the distance between the houses of group 2 and so on. You have to make sure the summation (x1+x2+x3+…+xn) is minimized.
Input
There will be many cases in the input file. Each case starts with an integer N (N ≤ 8). The next 2∗N
lines will given the information of the students. Each line starts with the students name, followed by
the x coordinate and then the y coordinate. Both x,y are integers in the range 0 to 1000. Students
name will consist of lowercase letters only and the length will be at most 20.
Input is terminated by a case where N is equal to 0.
Output
For each case, output the case number followed by the summation of the distances, rounded to 2 decimal
places. Follow the sample for exact format.
Sample Input
5
sohel 10 10
mahmud 20 10
sanny 5 5
prince 1 1
per 120 3
mf 6 6
kugel 50 60
joey 3 24
limon 6 9
manzoor 0 0
1
derek 9 9
jimmy 10 10
0
Sample Output
Case 1: 118.40
Case 2: 1.41
大意:
給你n*2個點座標,現在讓你把這些點變成n對,最後要求每對的距離的總和最小是多少。
#include <bits/stdc++.h>using namespace std;double dp[65536];struct Node{ double x,y;};Node node[20];double dist(int a,int b){ double x=node[a].x-node[b].x; double y=node[a].y-node[b].y; return sqrt(x*x+y*y);}int main(){ ios::sync_with_stdio(false); int n,k=0; while(cin>>n,n) { string ss; for(int i=0;i<2*n;i++) { cin>>ss; cin>>node[i].x>>node[i].y; } memset(dp,0,sizeof(dp)); for(int s=1;s<(1<<n*2);s++) { dp[s]=INT_MAX; int i; for(i=0;i<n*2;i++) if(s&(1<<i)) break; for(int j=i+1;j<n*2;j++) if(s&(1<<j)) dp[s]=min(dp[s],dist(i,j)+dp[s^(1<<i)^(1<<j)]); } cout<<"Case "<<++k<<": "; cout<<fixed<<setprecision(2)<<dp[(1<<n*2)-1]<<endl; } return 0;}
解答:
聽說過狀態壓縮這種方法的話,本題的轉移方程還是很好想出來的 。而且lrj的小白書和紫書上都有介紹,不過那本小白書和紫書好像都有錯誤,可以看勘誤表。
轉移方程是dp[s]=min(dp[s],dp[s^i^j]+dist(i,j))其中i=max(s),這裡光用狀態來表示,因為要枚舉到當前的兩個點i和j,把狀態s當中第一位1當做i,然後枚舉j即可。
另外,此題可以像lrj書上介紹的用二維數組表示dp[i][s]=min(dp[i-1][s^i^j]+dist(i,j)),這個轉移方程沒有疑問,可是我沒想明白書上代碼裡在枚舉全部狀態s的時候知道第i個點,也就是i一定在s中的狀態為1呢。