2010-1124

从 Trac 迁移的文章

这是从旧校内 Wiki 迁移的文章,可能存在一些样式问题,您可以向 memset0 反馈。

原文章内容如下:

Doraemon和Nobita出problem,每个problem由若干idea构成,若有两道题的idea重复数量超过一个限定并且这两道题分别来自Doraemon和Nobita,那么这两个problem算作重复,不能同时出现。
现在给定两个人的problem和每个problem的idea,求做多有几个problem

首先将所有problem放在一个集合里,然后去重,因为只有分别来自两个人的才可能重复,所以相当于求最大匹配数
由于idea可能达到1024,共有2^1024^-1种状态,所以进行状态压缩,将1024位分为32×32来存储每个problem的状态

代码如下:
{{{
#!python
#include <cstdio>
#include <memory.h>

using namespace std;

const int MaxN = 1001;
const int MaxL = 32;

bool graph[MaxN][MaxN];
bool visit[MaxN];
int match[MaxN];
int f[1<<16];
unsigned int D_idea[MaxN][MaxL];
unsigned int N_idea[MaxN][MaxL];
int n;
int m;
int t;
int l;

#define debug 0

void init(void)
{
    int n;
    int k;

    for (n=0; n<1<<16; ++n)
    {
        int temp = n;
        int sum(0);
        while (temp != 0)
        {
            sum += temp % 2;
            temp /= 2;
        }
        f[n] = sum;
    }

    return;
}

bool dfs(int k)
{
    int i;
    int temp;

    for (i=0; i<m; ++i)
    {
        if (graph[k][i] && !visit[i])
        {
            visit[i] = true;
            temp = match[i];

            if (temp == -1 || dfs(temp))
            {
                match[i] = k;
                return true;
            }
        }
    }

    return false;
}

int main(void)
{
    int i;
    int j;
    int k;
    int num;
    int id;

    init();

#if debug
    freopen("in.txt", "r", stdin);
#endif
    while (scanf("%d %d %d %d", &n, &m, &t, &l) != EOF)
    {
        memset(N_idea, 0, sizeof(N_idea));
        memset(D_idea, 0, sizeof(D_idea));
        memset(graph, false, sizeof(graph));
        for (i=0; i<n; ++i)
        {
            scanf("%d", &num);
            for (j=0; j<num; ++j)
            {
                scanf("%d", &id);
                --id;
                D_idea[i][id/32] += 1u << (id % 32);
            }
        }
        for (i=0; i<m; ++i)
        {
            scanf("%d", &num);
            for (j=0; j<num; ++j)
            {
                scanf("%d", &id);
                --id;
                N_idea[i][id/32] += 1u << (id % 32);
            }
        }
        //initial graph
        for (i=0; i<n; ++i)
        {
            for (j=0; j<m; ++j)
            {
                num = 0;
                for (k=0; k<MaxL; ++k)
                {
                    unsigned int temp = D_idea[i][k] & N_idea[j][k];
                    num += f[temp >> 16] + f[temp & 0x0000ffff];
                }
                if (num >= l)
                {
                    graph[i][j] = true;
                }
            }
        }

        num = 0;
        memset(match, -1, sizeof(match));
        for (i=0; i<n; ++i)
        {
            memset(visit, false, sizeof(visit));

            if (dfs(i))
            {
                ++num;
            }
        }

        printf("%d\n", n + m - num);
    }

    return 0;
}
}}}
[by delta_4d]

Doraemon和Nobita出problem,每个problem由若干idea构成,若有两道题的idea重复数量超过一个限定并且这两道题分别来自Doraemon和Nobita,那么这两个problem算作重复,不能同时出现。

现在给定两个人的problem和每个problem的idea,求做多有几个problem

首先将所有problem放在一个集合里,然后去重,因为只有分别来自两个人的才可能重复,所以相当于求最大匹配数

由于idea可能达到1024,共有21024-1种状态,所以进行状态压缩,将1024位分为32×32来存储每个problem的状态

代码如下:

#include <cstdio>
#include <memory.h>
using namespace std;
const int MaxN = 1001;
const int MaxL = 32;
bool graph[MaxN][MaxN];
bool visit[MaxN];
int match[MaxN];
int f[1<<16];
unsigned int D_idea[MaxN][MaxL];
unsigned int N_idea[MaxN][MaxL];
int n;
int m;
int t;
int l;
#define debug 0
void init(void)
{
    int n;
    int k;
    for (n=0; n<1<<16; ++n)
    {
        int temp = n;
        int sum(0);
        while (temp != 0)
        {
            sum += temp % 2;
            temp /= 2;
        }
        f[n] = sum;
    }
    return;
}
bool dfs(int k)
{
    int i;
    int temp;
    for (i=0; i<m; ++i)
    {
        if (graph[k][i] && !visit[i])
        {
            visit[i] = true;
            temp = match[i];
            if (temp == -1 || dfs(temp))
            {
                match[i] = k;
                return true;
            }
        }
    }
    return false;
}
int main(void)
{
    int i;
    int j;
    int k;
    int num;
    int id;
    init();
#if debug
    freopen("in.txt", "r", stdin);
#endif
    while (scanf("%d %d %d %d", &n, &m, &t, &l) != EOF)
    {
        memset(N_idea, 0, sizeof(N_idea));
        memset(D_idea, 0, sizeof(D_idea));
        memset(graph, false, sizeof(graph));
        for (i=0; i<n; ++i)
        {
            scanf("%d", &num);
            for (j=0; j<num; ++j)
            {
                scanf("%d", &id);
                --id;
                D_idea[i][id/32] += 1u << (id % 32);
            }
        }
        for (i=0; i<m; ++i)
        {
            scanf("%d", &num);
            for (j=0; j<num; ++j)
            {
                scanf("%d", &id);
                --id;
                N_idea[i][id/32] += 1u << (id % 32);
            }
        }
        //initial graph
        for (i=0; i<n; ++i)
        {
            for (j=0; j<m; ++j)
            {
                num = 0;
                for (k=0; k<MaxL; ++k)
                {
                    unsigned int temp = D_idea[i][k] & N_idea[j][k];
                    num += f[temp >> 16] + f[temp & 0x0000ffff];
                }
                if (num >= l)
                {
                    graph[i][j] = true;
                }
            }
        }
        num = 0;
        memset(match, -1, sizeof(match));
        for (i=0; i<n; ++i)
        {
            memset(visit, false, sizeof(visit));
            if (dfs(i))
            {
                ++num;
            }
        }
        printf("%d\n", n + m - num);
    }
    return 0;
}

[by delta_4d]