HDU 3362 Fix(状压DP)

Fix

Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 916    Accepted Submission(s): 309


Problem Description
There are a few points on a plane, and some are fixed on the plane, some are not. We want to connect these points by some sticks so that all the points are fixed on the plane. Of course, we want to know the minimum length of the sum of the sticks.

As in the images, the black points are fixed on the plane and red ones are not, which need to be fixed by sticks.
All the points in the left image have been fixed. But the middle one is not, which we need add one stick to fix those four points (the right image shows that stick). Triangle is steady, isn’t it?
 

Input
The input consists of multiply test cases. The first line of each test case contains one integer, n (1 <= n <= 18), which is the number of points. The next n lines, each line consists of three integers, x, y, c (0 <= x, y < 100). (x, y) indicate the coordinate of one point; c = 1 indicates this point is fixed; c = 0 indicates this point is not fixed. You can assume that no two points have the same coordinate.
The last test case is followed by a line containing one zero, which means the end of the input.
 

Output
Output the minimum length with six factional digits for each test case in a single line. If you cannot fix all the points, then output “No Solution”.
 

Sample Input
  
  
4 0 0 1 1 0 1 0 1 0 1 1 0 3 0 0 1 1 1 0 2 2 0 0
 

Sample Output
  
  
4.414214 No Solution
 

Source

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <vector>
#include <queue>
#include <set>
#include <algorithm>
#define LL long long
using namespace std;
const int MAXN = 20;
const double INF = 100000000.0;
struct Node
{
    int x, y;
}Point[MAXN];
int fix[MAXN], start, target, N;
double dis[MAXN], dp[1<<21];
double Dis(int a, int b)
{
    double x = (double)(Point[a].x - Point[b].x);
    double y = (double)(Point[a].y - Point[b].y);
    return sqrt(x * x + y * y);
}
double solve(int s, int x)
{
    int m = 0;
    for(int i=0;i<N;i++) if(s & (1 << i))
       dis[m++] = Dis(i, x);
    sort(dis, dis + m);
   // cout << m << endl;
    if(m < 2) return -1;
    double ans = dis[0] + dis[1];
    return ans;
}
int main()
{
    while(scanf("%d", &N)!=EOF && N)
    {
        start = target = 0;
        for(int i=0;i<N;i++)
        {
            scanf("%d%d%d", &Point[i].x, &Point[i].y, &fix[i]);
            if(fix[i]) start |= (1 << i);
            target |= (1 << i);
        }
        for(int i=0;i<=target;i++) dp[i] = INF;
        dp[start] = 0;
        for(int s=start;s<=target;s++)
        {
            if(dp[s] == INF) continue;
            for(int i=0;i<N;i++)
            {
                if(!(s & (1 << i)))
                {
                    double res = solve(s, i);
                    //cout << s << ' ' << i << ' ' << res << endl;
                    if(res >= 0) dp[s|(1<<i)] = min(dp[s|(1<<i)], dp[s] + res);
                   // cout << dp[s] << ' ' << dp[s|(1<<i)] << endl;
                }
            }
        }
        if(dp[target] >= INF) printf("No Solution\n");
        else printf("%.6lf\n", dp[target]);
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值