yzoj1891 最优配对问题 题解

题意

有n个点,且2|n,要求将其分为n/2对点对使得所有点对中距离之和尽量小

输出保留两位小数

考虑数据范围先想到的是搜索,然而搜索超时,我们发现在搜索的时候有重复搜索的情况,那么考虑记忆化,看到数据范围,便想到状压dp,每个点对应一个二进制位,未配对的记为1,已经配对的记为0。如n=8,未配对的点为1,3,5,7,则对应的二进制为01010101,对应的十进制为85,则把(1,3,5,7)配对的最小值存储在f[85]中。

那么我们可以写出状态转移方程

f[i]=min(f[i xor(1<<(x-1))xor(1<<(y-1))]+dis(x,y))

(i&(1<<(x-1))!=0)&(i&1<<(y-1))!=0)

然后这道题直接dp便可解决

#include<bits/stdc++.h>
using namespace std;
const int maxn=25;
const int INF=1000000;
struct node{
    int x;
    int y;
}a[maxn];
int n,S;
double dis[maxn][maxn],d[(1<<20)+5];
void ins(){
    for(int i=1;i<=n;++i){
        for(int j=i+1;j<=n;++j){
            dis[i][j]=dis[j][i]=sqrt((a[i].x-a[j].x)*(a[i].x-a[j].x)+(a[i].y-a[j].y)*(a[i].y-a[j].y));
        }
    }
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;++i){
        scanf("%d %d",&a[i].x,&a[i].y);
    }
    ins();
    for(int S=1;S<=(1<<n)-1;S++){
        d[S]=INF;
        int i;
        for(i=1;i<=n-1;++i){
            if(S&(1<<(i-1))) break;
        }
        for(int j=i+1;j<=n;j++){
            if(S&(1<<(j-1))) d[S]=min(d[S],dis[i][j]+d[S^(1<<(i-1))^(1<<(j-1))]);
        }
    }    
    printf("%.2lf",d[(1<<n)-1]);
    return 0;
}
/*
4
8730 9323
-3374 3929
-7890 -6727
1257 4689
*/

转载于:https://www.cnblogs.com/donkey2603089141/p/11414892.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值