hdu3957Street Fighter(DLX重复覆盖)

题目请戳这里

题目大意:在游戏Street Fighter(街头霸王)中有若干个角色,每个角色有1~2个模式,每个角色在某个模式下可以KO另外某些模式下的某些角色。现在给n个角色和他们的模式以及各自在相应模式下能KO的对手及对手的模式。求最少需要几个角色能KO所有其他角色。

题目分析:重复覆盖问题,DLX解决。因为每个角色有1~2个模式,所以抽象出2*n行和2*n列。直接建图跑DLX即可。

需要注意的问题:

1:每个角色要对自己建边,因为自己不需要KO。

2:有的角色没有model2,所以建图后要把没有列元素的列头删掉(此处wa数次!!)

3:要判重,一个角色只能选一次。

详情请见代码:

#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 3000;
int n,num;
bool vis[55];
bool flag[55];
int data[55][55];
int ans;
int h[N],s[N],u[N],d[N],l[N],r[N],row[N],col[N];
int lim;
int md[26];
void init(int tn)
{
    memset(h,0,sizeof(h));
    memset(s,0,sizeof(s));
    memset(flag,false,sizeof(flag));
    for(int i = 0;i <= tn;i ++)
    {
        u[i] = d[i] = i;
        l[i] = (i + tn) % (tn + 1);
        r[i] = (i + 1) % (tn + 1);
    }
    num = tn + 1;
}
void build(int i,int j)
{
    if(h[i])
    {
        r[num] = h[i];
        l[num] = l[h[i]];
        r[l[num]] = l[r[num]] = num;
    }
    else
        h[i] = l[num] = r[num] = num;
    s[j] ++;
    u[num] = u[j];
    d[num] = j;
    d[u[num]] = num;
    u[j] = num;
    col[num] = j;
    row[num] = i;
    num ++;
}
void prepare()
{
    scanf("%d",&n);
    int i,j,m,k,a,b;
    init(n + n);
    memset(md,0,sizeof(md));
    memset(data,0,sizeof(data));
    for(i = 0;i < n;i ++)
    {
        scanf("%d",&md[i]);
        data[i<<1|1][i<<1|1] = 1;
        for(j = 1;j <= md[i];j ++)
        {
            scanf("%d",&m);
            while(m --)
            {
                scanf("%d%d",&a,&b);
                data[(i<<1)+j][(a<<1)+b+1] = 1;
            }
        }
        if(md[i] == 2)
        {
            data[i<<1|1][(i<<1)+2] = 1;
            data[(i<<1)+2][(i<<1)+2] = 1;
            data[(i<<1)+2][i<<1|1] = 1;
        }
    }
    for(i = 2;i <= n + n;i += 2)//!!!!!!!删除没有模式2的列头!!!
        if(md[(i>>1)-1] == 1)
            r[l[i]] = r[i],l[r[i]] = l[i];
    for(i = 1;i <= n + n;i ++)
    {
        for(j = 1;j <= n + n;j ++)
        {
            if(data[i][j])
            {
                build(i,j);
            }
        }
    }
}
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]] = r[l[i]] = i;
}
int A()
{
    int i,j,k,ret = 0;
    memset(vis,false,sizeof(vis));
    for(i = r[0];i;i = r[i])
    {
        if(vis[i] == false)
        {
            ret ++;
            vis[i] = true;
            for(j = d[i];j != i;j = d[j])
                for(k = r[j];k != j;k = r[k])
                    vis[col[k]] = true;
        }
    }
    return ret;
}
void dfs(int k)
{
    if(k + A() >= ans)
        return ;
    if(!r[0])
    {
        ans = min(ans,k);
        return ;
    }
    int i,j,c,mn = N;
    for(i = r[0];i;i = r[i])
    {
        if(s[i] < mn)
        {
            mn = s[i];
            c = i;
        }
    }
    for(i = d[c];i != c;i = d[i])
    {
        if(flag[(row[i] + 1)>>1] == true)
            continue;
        remove(i);
        flag[(row[i] + 1)>>1] = true;
        for(j = r[i];j != i;j = r[j])
            remove(j);
        dfs(k + 1);
        for(j = l[i];j != i;j = l[j])
            resume(j);
        resume(i);
        flag[(row[i] + 1)>>1] = false;
    }
}
void dance(int cas)
{
    ans = n;
    dfs(0);
    printf("Case %d: %d\n",cas,ans);
}
int main()
{
    int _,cas = 0;
    scanf("%d",&_);
    while(_ --)
    {
        prepare();
        dance(++cas);
    }
    return 0;
}
//1937MS	340K


你可能感兴趣的:(搜索)