• 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
    */
    
  • 相关阅读:
    Activiti-流程定义
    Activiti入门案例
    工作流--Activiti
    并发编程面试题
    CAS无锁机制
    Activiti个人流程和流量变化
    工作流——Activiti案例
    工作流——Activiti
    并发编程面试题
    锁机制-AQS和CAS
  • 原文地址:https://www.cnblogs.com/donkey2603089141/p/11414892.html
Copyright © 2020-2023  润新知