【DLX】 hdu3957 Street Fighter

Street Fighter

题目:http://acm.hdu.edu.cn/showproblem.php?pid=3957

题意:模拟街头霸王游戏(我都没玩过T-T),有N(2<=N<=25)个角色,每个人都有M(1<=M<=2)个模式,同时告诉你每个角色在某个模式可以击败其他的在某个模式的某个角色,问你最少选择几个角色可以击败其他所有角色,无论其他角色在什么模式下。

题解:DLX的重复覆盖问题,但是要考虑一个角色有多个模式,而且每个角色只能选择一次。

           1)同时使用重复覆盖和精确覆盖。

           2)只用重复覆盖,同时使用一个数组记录使用了什么角色。

           代码是实现第二种。

代码:

#include<cstdio>
#include<cstring>
#include<climits>
#define N 55
#define M 2525
using namespace std;
struct
{
    int col,row;
} node[M];
int l[M],r[M],d[M],u[M],h[M],res[N],cntcol[N];
int dcnt=-1,minn;
int n,m;
bool visit[N];//标记使用哪个角色的哪个模式
int H()//a*加速
{
    int count=0;
    bool hash[N];
    memset(hash,false,sizeof(hash));
    for(int i=r[0]; i!=0; i=r[i])
    {
        if(hash[i]) continue;
        hash[i]=true;
        count++;
        for(int j=d[i]; j!=i; j=d[j])
            for(int k=r[j]; k!=j; k=r[k])
                hash[node[k].col]=true;
    }
    return count;
}
void addnode(int &x)
{
    ++x;
    r[x]=l[x]=u[x]=d[x]=x;
}
void insert_row(int rowx,int x)
{
    r[l[rowx]]=x;
    l[x]=l[rowx];
    r[x]=rowx;
    l[rowx]=x;
}
void insert_col(int colx,int x)
{
    d[u[colx]]=x;
    u[x]=u[colx];
    d[x]=colx;
    u[colx]=x;
}
void dlx_init(int cols)
{
    memset(h,-1,sizeof(h));
    memset(cntcol,0,sizeof(cntcol));
    dcnt=-1;
    addnode(dcnt);
    for(int i=1; i<=cols; ++i)
    {
        addnode(dcnt);
        insert_row(0,dcnt);
    }
}
void insert_node(int x,int y)
{
    cntcol[y]++;
    addnode(dcnt);
    node[dcnt].row=x;
    node[dcnt].col=y;
    insert_col(y,dcnt);
    if(h[x]==-1) h[x]=dcnt;
    else insert_row(h[x],dcnt);
}
void remove(int c)
{
    for(int i=d[c]; i!=c; i=d[i])
    {
        l[r[i]]=l[i];
        r[l[i]]=r[i];
    }
}
void resume(int c)
{
    for(int i=u[c]; i!=c; i=u[i])
    {
        l[r[i]]=i;
        r[l[i]]=i;
    }
}
void DLX(int deep)
{
    if(deep+H()>=minn) return;
    if(r[0]==0)
    {
        if(minn>deep) minn=deep;
        return;
    }
    int min=INT_MAX,tempc;
    for(int i=r[0]; i!=0; i=r[i])
        if(cntcol[i]<min)
        {
            min=cntcol[i];
            tempc=i;
        }
    for(int i=d[tempc]; i!=tempc; i=d[i])
    {
        if(visit[node[i].row]) continue;
        res[deep]=node[i].row;//选择某个角色的某个模式
        remove(i);
        for(int j=r[i]; j!=i; j=r[j]) remove(j);
        visit[node[i].row]=true;
        if(m==2)
        {
            if((node[i].row%2)&1)
                visit[node[i].row+1]=true;
            else
                visit[node[i].row-1]=true;
        }
        DLX(deep+1);
        visit[node[i].row]=false;
        if(m==2)
        {
            if((node[i].row%2)&1)
                visit[node[i].row+1]=false;
            else
                visit[node[i].row-1]=false;
        }
        for(int j=l[i]; j!=i; j=l[j]) resume(j);
        resume(i);
    }
    return;
}
int main()
{
    int k,T;
    int a,b;
    scanf("%d",&T);
    for(int cas=1; cas<=T; ++cas)
    {
        minn=INT_MAX;
        memset(visit,false,sizeof(visit));
        scanf("%d",&n);
        scanf("%d",&m);
        dlx_init(n*m);
        //选择一个角色可以覆盖他所有的模式
        for(int i=0; i<n; ++i)
            for(int j=0; j<m; ++j)
                for(int k=0; k<m; ++k)
                    insert_node(i*m+j+1,i*m+k+1);
        for(int i=0; i<m; ++i)
        {
            scanf("%d",&k);
            for(; k--;)
            {
                scanf("%d%d",&a,&b);
                insert_node(i+1,a*m+b+1);
            }
        }
        for(int i=1; i<n; ++i)
        {
            scanf("%d",&m);
            for(int j=0; j<m; ++j)
            {
                scanf("%d",&k);
                for(; k--;)
                {
                    scanf("%d%d",&a,&b);
                    insert_node(i*m+j+1,a*m+b+1);
                }
            }
        }
        DLX(0);
        printf("Case %d: %d\n",cas,minn);
    }
    return 0;
}

来源: http://blog.csdn.net/ACM_Ted

你可能感兴趣的:(【DLX】 hdu3957 Street Fighter)