HDU 2295 Radar (二分 + Dancing Links 重复覆盖模型 )

 以下转自 这里

最小支配集问题:二分枚举最小距离,判断可行性。可行性即重复覆盖模型,DLX解之。 

A*的启发函数: 

对当前矩阵来说,选择一个未被控制的列,很明显该列最少需要1个行来控制,所以ans++。 

该列被控制后,把它所对应的行,全部设为已经选择,并把这些行对应的列也设为被控制。继续选择未被控制的列,直到没有这样的列。

#include <cstdio>

#include <cstring>

#include <cstdlib>

#include <cmath>

#include <algorithm>



using namespace std;



const double eps = 1e-9;

const int INF = 1 << 30;

const int MAXN = 60;



struct Point

{

    double x, y;

    Point( double x = 0, double y = 0 ):x(x), y(y) { }

    void readPoint()

    {

        scanf( "%lf%lf", &x, &y );

        return;

    }

};



Point city[MAXN];

Point radar[MAXN];



int N, M, K;

int L[MAXN*MAXN], R[MAXN*MAXN];

int U[MAXN*MAXN], D[MAXN*MAXN];

int C[MAXN*MAXN], cnt[MAXN];

bool mx[MAXN][MAXN];

bool vis[MAXN];

int head;



void Remove( int c )

{

    for ( int i = D[c]; i != c; i = D[i] )

    {

        R[ L[i] ] = R[i];

        L[ R[i] ] = L[i];

    }

    return;

}



void Resume( int c )

{

    for ( int i = D[c]; i != c; i = D[i] )

    {

        R[ L[i] ] = i;

        L[ R[i] ] = i;

    }

    return;

}



//估价函数:至少还需要选择几个雷达

int h()

{

    memset( vis, false, sizeof(vis) );

    int res = 0;

    for ( int c = R[head]; c != head; c = R[c] )

    {

        if ( !vis[c] )

        {

            ++res;

            for ( int i = D[c]; i != c; i = D[i] )

                for ( int j = R[i]; j != i; j = R[j] )

                    vis[ C[j] ] = true;

        }

    }

    return res;

}



bool DFS( int dep )

{

    if ( R[head] == head ) return true;

    if ( dep + h() > K ) return false;

    int minv = INF, c;



    for ( int i = R[head]; i != head; i = R[i] )

    {

        if ( cnt[i] < minv )

        {

            minv = cnt[i];

            c = i;

        }

    }



    for ( int i = D[c]; i != c; i = D[i] )

    {

        Remove(i);

        for ( int j = R[i]; j != i; j = R[j] )

        {

            Remove(j);

            --cnt[ C[j] ];

        }

        if ( DFS( dep + 1 ) ) return true;

        for ( int j = R[i]; j != i; j = R[j] )

        {

            Resume(j);

            ++cnt[ C[j] ];

        }

        Resume(i);

    }



    return false;

}



bool build()

{

    head = 0;

    for ( int i = 0; i < N; ++i )

    {

        R[i] = i + 1;

        L[i + 1] = i;

    }

    R[N] = 0;

    L[0] = N;



    //列链表

    for ( int j = 1; j <= N; ++j )

    {

        int pre = j;

        cnt[j] = 0;

        for ( int i = 1; i <= M; ++i )

        {

            if ( mx[i][j] )

            {

                ++cnt[j];

                int cur = i * N + j;

                D[pre] = cur;

                U[cur] = pre;

                C[cur] = j;

                pre = cur;

            }

        }

        U[j] = pre;

        D[pre] = j;

        if ( !cnt[j] ) return false;

    }



    for ( int i = 1; i <= M; ++i )

    {

        int pre = -1;

        int first = -1;

        for ( int j = 1; j <= N; ++j )

        {

            if ( mx[i][j] )

            {

                int cur = i * N + j;

                if ( pre == -1 ) first = cur;

                else

                {

                    R[pre] = cur;

                    L[cur] = pre;

                }

                pre = cur;

            }

        }

        if ( first != -1 )

        {

            L[first] = pre;

            R[pre] = first;

        }

    }

    return true;

}



/*************以上DLX模板***************/



double PointDis( Point a, Point b )

{

    return sqrt( (a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y) );

}



int dcmp( double x )    //控制精度

{

    if ( fabs(x) < eps ) return 0;

    else return x < 0 ? -1 : 1;

}



bool check( double mid )

{

    memset( mx, false, sizeof(mx) );



    for ( int i = 1; i <= M; ++i )

        for ( int j = 1; j <= N; ++j )

        {

            if ( dcmp( PointDis( radar[i], city[j] ) - mid ) < 0 )

                mx[i][j] = true;

        }



    if ( build() ) return DFS(0);

    return false;

}



double solved()

{

    double l = 0.0;

    double r = 1500.0;

    double ans;

    while ( dcmp( r - l ) > 0 )

    {

        double mid = (l + r) / 2.0;

        if ( check( mid ) )

        {

            r = mid;

            ans = mid;

        }

        else l = mid;

    }

    return ans;

}



int main()

{

    int T;

    scanf( "%d", &T );

    while ( T-- )

    {

        scanf( "%d%d%d", &N, &M, &K );

        for( int i = 1; i <= N; ++i )

            city[i].readPoint();

        for ( int i = 1; i <= M; ++i )

            radar[i].readPoint();



        printf( "%.6f\n", solved() );

    }

    return 0;

}

 

你可能感兴趣的:(link)