HDU - 3585 maximum shortest distance 最大团高效模板 + 二分

题意: 从n个点中选取k个点,使得在选取的所有边的距离中最短的最长,求出这个距离。

如果看成一个图的话就可以全部连边成完全图,就可以二分答案用最大团去做。

图论真的是模板效率重要哇,刚一开始我的板子一直t。。。

链接:hdu - 3585

AC代码:

/*
最大团 = 补图G的最大独立集数
———>最大独立集数 = 补图G'最大团
*/
//最大团模板
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <set>
#include <map>
#include <stack>
#include <queue>
#define inf 0x3f3f3f3f

using namespace std;

const int maxn = 105;

int mx;//最大团数(要初始化为0)
int vis[maxn], tuan[maxn];
int can[maxn][maxn];//can[i]表示在已经确定了经选定的i个点必须在最大团内的前提下还有可能被加进最大团的结点集合
int num[maxn];//num[i]表示由结点i到结点n构成的最大团的结点数
bool g[maxn][maxn];//邻接矩阵(从1开始)
int n, m;

bool dfs(int tot, int cnt) {
    if(tot == 0) {
        if(cnt > mx) {
            mx = cnt;
            for(int i = 0; i < mx; i++) {
                tuan[i] = vis[i];
            }
            return true;
        }
        return false;
    }
    for(int i = 0; i < tot; i++) {
        if(cnt + (tot - i) <= mx) return false;
        if(cnt + num[can[cnt][i]] <= mx) return false;
        int k = 0;
        vis[cnt] = can[cnt][i];
        for(int j = i + 1; j < tot; j++) {
            if(g[can[cnt][i]][can[cnt][j]]) {
                can[cnt + 1][k++] = can[cnt][j];
            }
        }
        if(dfs(k, cnt + 1)) return false;
    }
    return false;
}

void maxclique() {
    mx = 1;
    for(int i = n; i >= 1; i--) {
        int k = 0;
        vis[0] = i;
        for(int j = i + 1; j <= n; j++) {
            if(g[i][j]) {
                can[1][k++] = j;
            }
        }
        dfs(k, 1);
        num[i] = mx;
    }
}

int x[maxn], y[maxn];
int s[maxn][maxn];

int dist(int i, int j) {
    return (x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]);
}

int main()
{
    int k;
    while(~scanf("%d %d", &n, &k)) {
        memset(s, 0, sizeof(s));
        int l = 0, r = 0;
        for(int i = 1; i <= n; i++) {
            scanf ("%d %d", &x[i], &y[i]);
            for(int j = 1; j < i; j++) {
                s[i][j] = s[j][i] = dist(i, j);
                if(r < s[i][j])
                    r = s[i][j];
            }
        }
        //cout << r << endl;
        int mid;
        while(l <= r) {
            memset(g, 0, sizeof(g));
            for(int i = 1; i <= n; i++) {
                for(int j = 1; j < i; j++) {
                    if(s[i][j] >= mid) {
                        g[i][j] = g[j][i] = 1;
                    }
                }
            }
            maxclique();//求最大团
            if(mx >= k) {
                l = mid + 1;
            }
            else if(mx < k) {
                r = mid - 1;
            }
            mid = (l + r) / 2;
        }
        //cout << mid << endl;
        printf("%.2lf\n", sqrt(mid));
        /*for(int i = 0; i < mx; i++)
            printf( i == 0 ? "%d" : " %d", group[i]); //group[maxn]用以寻找一个最大团集合
        if( ans > 0 ) puts("");*/
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值