HDU 2295 Radar

HDU_2295

    第一次正式写Dancing Links解重复覆盖的问题,感觉和精确覆盖相比,精确覆盖要求每列只能有1一个1,因此在删除一列的时候要连带删除这一列中为1的所有行,同时要将选出的行中为1的列全部删除,而重复覆盖问题每列可以有多个1,但一旦选择了某一行,这一行上所有为1的列就可以纳入不考虑的范围了,因此删除操作就变成了删除某一行并删除这一行中为1的所有列。

    此外,如果是裸的Dancing Links会超时,于是考虑剪枝。假设当前还能搜k步,那么随便挑一列,这列是一定要被覆盖的,而在覆盖这列的同时还最多能覆盖多少其他的列呢?不妨把这列为1的所有行合并看成1行,然后把它们能够覆盖到的列都标记一下,看成是覆盖这一列的同时能够覆盖到的其他的列。反复执行这样的操作就可以得到一个期望的覆盖完所有列所需的最少行数,如果这个值都比k大的话,显然最后在k步是不可能覆盖完所有列的,于是就可以剪枝了。

#include<stdio.h>
#include<string.h>
#define MAXN 60
#define MAXD 3610
#define INF 0x3f3f3f3f
struct Point
{
    int x, y;    
}city[MAXN], radar[MAXN];
int N, M, K, size, U[MAXD], D[MAXD], R[MAXD], L[MAXD], C[MAXD];
int S[MAXN], H[MAXN];
void init()
{
    int i;
    scanf("%d%d%d", &N, &M, &K);
    for(i = 1; i <= N; i ++) scanf("%d%d", &city[i].x, &city[i].y);
    for(i = 1; i <= M; i ++) scanf("%d%d", &radar[i].x, &radar[i].y);
}
void prep(int n, int m)
{
    int i;
    for(i = 0; i <= m; i ++)
    {
        R[i] = i + 1, L[i + 1] = i;
        U[i] = D[i] = i, S[i] = 0;
    }
    R[m] = 0, size = m;
    for(i = 0; i <= n; i ++) H[i] = -1;
}
void insert(int r, int c)
{
    ++ size;
    C[size] = c, ++ S[c];
    D[size] = D[c], U[size] = c, U[D[c]] = size, D[c] = size;
    if(H[r] == -1) L[size] = R[size] = size, H[r] = size;
    else L[size] = H[r], R[size] = R[H[r]], L[R[H[r]]] = size, R[H[r]] = size;
}
inline double sqr(double x)
{
    return x * x;    
}
void build(double dis)
{
    int i, j;
    prep(M, N);    
    for(i = 1; i <= M; i ++)
        for(j = 1; j <= N; j ++)
            if(sqr(radar[i].x - city[j].x) + sqr(radar[i].y - city[j].y) <= sqr(dis))
                insert(i, j);
}
void remove(int c)
{
    int i;
    for(i = D[c]; i != c; i = D[i])
        L[R[i]] = L[i], R[L[i]] = R[i];
}
void resume(int c)
{
    int i;
    for(i = U[c]; i != c; i = U[i])
        L[R[i]] = i, R[L[i]] = i;
}
int least()
{
    int i, j, k, vis[MAXN], ans = 0;
    memset(vis, 0, sizeof(vis[0]) * (N + 1));
    for(i = R[0]; i != 0; i = R[i])
        if(!vis[i])
        {
            ++ ans;
            for(j = D[i]; j != i; j = D[j])
                for(k = R[j]; k != j; k = R[k]) vis[C[k]] = 1; 
        }
    return ans;
}
int dance(int k)
{
    if(R[0] == 0) return 1;    
    if(least() > k) return 0;
    int i, j, id, t = INF;
    for(i = R[0]; i != 0; i = R[i])
        if(S[i] < t) t = S[i], id = i;
    for(i = D[id]; i != id; i = D[i])
    {
        remove(i);
        for(j = R[i]; j != i; j = R[j]) remove(j);
        if(dance(k - 1)) return 1;
        for(j = L[i]; j != i; j = L[j]) resume(j);
        resume(i);
    }
    return 0;    
}
void solve()
{
    int t = 100;
    double mid, min = 0, max = 2000;
    while(t --)
    {
        mid = (min + max) * 0.5;
        build(mid);
        if(dance(K)) max = mid;
        else min = mid;
    }
    printf("%.6f\n", mid);
}
int main()
{
    int t;
    scanf("%d", &t);
    while(t --)
    {
        init();
        solve();    
    }
    return 0;    
}
原文地址:https://www.cnblogs.com/staginner/p/2665006.html