[HDU 4735 Little Wish~ lyrical step~] DLX + A*优化搜索

题目

acm.hdu.edu.cn/showproblem.php?pid=4735

分析

Dancing Links 解决重复覆盖问题

先用Floyd求两点间最短距离,将<=D的连边(注意自己要跟自己连边)。

用DLX暴力搜索出所有可行的状态,更新最小值。

中间用A*进行乐观估计,如果当前用的男孩数量+估计还需要的男孩数量 > 男孩总数则return

800+msAC

代码

#include<cstring>
#include<string>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<vector>
#include<cmath>
#include<algorithm>
using namespace std;
#define ll long long
#define pf printf
#define sf scanf
#define  Fill(a,b) memset(a,b,sizeof(a))
const int N = 3000;
const int inf = 1e9;
int L[N],R[N],D[N],U[N],S[N],nCol[N];
int a[N];
int b[55][55];
int judge[N];
int n,best,num,head,dd;
int boys,girls;
bool vis[55];
inline void Floyd()
{
    for (int k = 1; k <= n; k++)
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
                if (b[i][j] > b[i][k] + b[k][j]) b[i][j] = b[i][k] + b[k][j];
}
inline void init()
{
    for (int i=0;i<=n;i++)
    {
        L[i]=i-1; R[i]=i+1;
        U[i]=D[i]=i;
    }
    L[0]=n; R[n]=0;

    int cnt=n+1;
    for (int i=1;i<=n;i++)
    {
        int head=cnt,tail=cnt;
        for (int j=1;j<=n;j++)
        if (b[i][j] == 1)
        {
            int c = j;
            S[c]++;
            nCol[cnt]=c;

            U[D[c]]=cnt;
            D[cnt]=D[c];
            U[cnt]=c;
            D[c]=cnt;

            L[cnt]=tail; R[tail]=cnt;
            R[cnt]=head; L[head]=cnt;
            tail=cnt;
            judge[cnt] = i;
            cnt++;
        }
    }
}

inline void Remove(int x)
{
    for (int i=D[x];i!=x;i=D[i])
    {
        L[R[i]]=L[i];
        R[L[i]]=R[i];
        S[nCol[i]]--;
    }
}

inline void Resume(int x)
{
    for (int i=U[x];i!=x;i=U[i])
    {
        L[R[i]]=R[L[i]]=i;
        S[nCol[i]]++;
    }
}

inline int A_star()
{
    Fill(vis,0);
    int ret = 0;
    for(int i = R[0]; i != 0; i = R[i])
    if(!vis[i])
    {
        ++ret;
        for(int j = D[i]; j != i; j = D[j])
        {
            for(int k = R[j]; k != j; k = R[k]) vis[nCol[k]] = true;
        }
    }
    return ret;
}
void dfs(int ans,int sum)
{
    //cout<<R[0]<<endl;
   // cout<<ans<<" "<<best<<endl;
    //if (tf > boys) return;
    if (sum + A_star() > boys) return;
    if (ans >= best) return;
    if (R[0]==0)
    {
        best=ans;
        return;
    }
    if (sum ==  boys) return;
    int c,minnum=inf;
    for (int i=R[0];i!=0;i=R[i])
    {
        if (S[i]==0) return;
        if (S[i]<minnum)
        {
            minnum=S[i];
            c=i;
        }
    }

    for (int i=U[c];i!=c;i=U[i])
    {
        Remove(i);
        for (int j=R[i];j!=i;j=R[j]) Remove(j);
        //cout<<i<<" "<<judge[i]<<endl;
        //tf++;
        dfs(ans+(a[judge[i]] == 0),sum + 1);
        //tf--;
        for (int j=L[i];j!=i;j=L[j]) Resume(j);
        Resume(i);
    }
}
int main()
{
    //freopen("in.txt","r",stdin);
    int T; sf("%d",&T);
    for (int TT = 1; TT <= T; TT++)
    {
        sf("%d%d",&n,&dd);
        boys = 0,girls = 0;
        for (int i = 1; i <= n; i++)
        {
            sf("%d",&a[i]);
            boys += (a[i] == 1);
            girls += (a[i] == 0);
        }
        Fill(b,63);
        for (int i = 1; i < n; i++)
        {
            int x,y,z;
            sf("%d%d%d",&x,&y,&z);
            b[x][y] = b[y][x] = z;
        }
        for (int i = 1; i <= n; i++) b[i][i] = 0;
        Floyd();
        for (int i = 1; i<= n; i++)
            for (int j = 1; j <= n; j++)
                if (b[i][j] <= dd) b[i][j] = 1; else b[i][j] = 0;
        //cout<<n<<endl; continue;
        //for (int i = 1; i <= n; i++)
            //for (int j = 1; j <= n; j++) cout<<i<<" "<<j<<" "<<b[i][j]<<endl;
        init();
        best = 1e9;
        dfs(0,0);
        if (best == 1e9) best = -1;
        pf("Case #%d: %d\n",TT,best);
    }
    return 0;
}


你可能感兴趣的:([HDU 4735 Little Wish~ lyrical step~] DLX + A*优化搜索)