UVa:10911 Forming Quiz Teams(状态压缩)

思路:集合上的动态规划。

就这个题目而言,用整数表示的集合可以很好的表现除去某个元素的集合这种特点。

集合中的元素已经隐含了阶段,集合是从较小的子集逐渐枚举到较大的子集的,正符合动规的特点。

另外注意用整数表示集合,数组要开到比1<<n大。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <cmath>
#include <queue>
#include <algorithm>
#define ll long long
#define INF 1e10//2139062143
#define inf -2139062144
#define MOD 20071027
#define MAXN 20
using namespace std;
int n;
int x[MAXN],y[MAXN];
double dp[1000005],dis[MAXN][MAXN];
bool vis[1000005];
double distance(double x1,double y1,double x2,double y2)
{
    return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
double DP(int S)
{
    if(vis[S]||!S) return dp[S];
    vis[S]=true;
    int i;
    for(i=n-1; i>=0; --i)
        if(S&(1<<i)) break;
    dp[S]=INF;
    for(int j=i-1; j>=0; --j)
        if(S&(1<<j))
        dp[S]=min(dp[S],dis[i][j]+DP(S^(1<<i)^(1<<j)));
    return dp[S];
}
int main()
{
    int kase=0;
    dp[0]=0;
    while(scanf("%d",&n)&&n)
    {
        n=n<<1;
        char str[25];
        for(int i=0; i<n; ++i)
            scanf("%s%d%d",str,&x[i],&y[i]);
        for(int i=0; i<n; ++i)
            for(int j=i+1; j<n; ++j)
                dis[i][j]=dis[j][i]=distance(x[i],y[i],x[j],y[j]);
        memset(vis,0,sizeof(vis));
        printf("Case %d: %.2lf\n",++kase,DP((1<<n)-1));
    }
    return 0;
}


 

你可能感兴趣的:(uva,状态压缩)