uva 10911Forming Quiz Teams

来源:互联网 发布:淘宝网男士保暖上衣 编辑:程序博客网 时间:2024/05/23 14:31

原题:
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呢?

0 0
原创粉丝点击