The Perfect Stall_usaco4.2_匹配

本文介绍了一种使用匈牙利算法解决牛棚分配问题的方法,该问题涉及为不同偏好奶牛找到最优分配方案,确保尽可能多的奶牛能够在其偏好的牛栏中产奶。

Description


  农夫约翰上个星期刚刚建好了他的新牛棚,他使用了最新的挤奶技术。不幸的是,由于工程问题,每个牛栏都不一样。第一个星期,农夫约翰随便地让奶牛们进入牛栏,但是问题很快地显露出来:每头奶牛都只愿意在她们喜欢的那些牛栏中产奶。上个星期,农夫约翰刚刚收集到了奶牛们的爱好的信息(每头奶牛喜欢在哪些牛栏产奶)。一个牛栏只能容纳一头奶牛,当然,一头奶牛只能在一个牛栏中产奶。
  给出奶牛们的爱好的信息,计算最大分配方案。

Input


第一行 两个整数,N (0 <= N <= 200) 和 M (0 <= M <= 200) 。N 是农夫约翰的奶牛数量,M 是新牛棚的牛栏数量。
第二行到第N+1行 一共 N 行,每行对应一只奶牛。第一个数字 (Si) 是这头奶牛愿意在其中产奶的牛栏的数目 (0 <= Si <= M) 。后面的 Si 个数表示这些牛栏的编号。牛栏的编号限定在区间 (1..M) 中,在同一行,一个牛栏不会被列出两次。

Output


只有一行。输出一个整数,表示最多能分配到的牛栏的数量。

Analysis


二分图的最大匹配,匈牙利搞定

Code


#include <stdio.h>
#include <cstring>
using namespace std;
struct edge
{
    int x,y,next;
}e[40100];
int link[210],ls[40100],maxE=0;
bool vis[210];
void add(int x,int y)
{
    e[++maxE]=(edge){x,y,ls[x]};
    ls[x]=maxE;
}
int find(int x)
{
    for (int i=ls[x];i;i=e[i].next)
    {
        if (!vis[e[i].y])
        {
            vis[e[i].y]=true;
            if (find(link[e[i].y])||!link[e[i].y])
            {
                link[e[i].y]=x;
                return 1;
            }
        }
    }
    return 0;
}
int main()
{
    int n,m,ans=0;
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++)
    {
        int tmp,y;
        scanf("%d",&tmp);
        while (tmp--)
        {
            scanf("%d",&y);
            add(i,y);
        }
    }
    for (int i=1;i<=n;i++)
    {
        memset(vis,false,sizeof(vis));
        ans+=find(i);
    }
    printf("%d\n",ans);
    return 0;
}
<think>我们有两个逻辑表达式: assign not_txdat_stall_d1 = (~txdat_sched_pend_v_dx & ~ram_pipe_fifo_pfull & ~ram_pipe_fifo_push) | (not_txdat_stall_d2 & ~ram_pipe_fifo_push); assign not_txdat_stall_d2 = ~tmp_txdat_flit_v_d3 | ~ram_pipe_fifo_pfull; 现在,我们想要在以下赋值中直接代入这两个表达式: assign block_txdat_sched_v_d2 = (~not_txdat_stall_d1 & ~not_txdat_stall_d2); 因此,我们需要将not_txdat_stall_d1和not_txdat_stall_d2用它们各自的表达式替换,然后进行化简。 步骤: 1. 首先,将not_txdat_stall_d2代入not_txdat_stall_d1的表达式中。 2. 然后,将两个表达式代入block_txdat_sched_v_d2的表达式,并化简。 注意:在代入时,由于逻辑表达式可能变得复杂,我们需要小心处理。 开始: 第一步:代入not_txdat_stall_d2到not_txdat_stall_d1中。 令: not_txdat_stall_d2 = ~tmp_txdat_flit_v_d3 | ~ram_pipe_fifo_pfull; 代入not_txdat_stall_d1: not_txdat_stall_d1 = (~txdat_sched_pend_v_dx & ~ram_pipe_fifo_pfull & ~ram_pipe_fifo_push) | (not_txdat_stall_d2 & ~ram_pipe_fifo_push) = (~txdat_sched_pend_v_dx & ~ram_pipe_fifo_pfull & ~ram_pipe_fifo_push) | ((~tmp_txdat_flit_v_d3 | ~ram_pipe_fifo_pfull) & ~ram_pipe_fifo_push); 第二步:将not_txdat_stall_d1和not_txdat_stall_d2代入block_txdat_sched_v_d2。 block_txdat_sched_v_d2 = ~not_txdat_stall_d1 & ~not_txdat_stall_d2 注意:~not_txdat_stall_d1 和 ~not_txdat_stall_d2 分别是 not_txdat_stall_d1 和 not_txdat_stall_d2 的取反。 所以,我们需要分别求反: 首先,求反not_txdat_stall_d2: ~not_txdat_stall_d2 = ~(~tmp_txdat_flit_v_d3 | ~ram_pipe_fifo_pfull) = tmp_txdat_flit_v_d3 & ram_pipe_fifo_pfull [因为 ~(A|B) = ~A & ~B,而这里A=~tmp_txdat_flit_v_d3, B=~ram_pipe_fifo_pfull,所以~A=tmp_txdat_flit_v_d3, ~B=ram_pipe_fifo_pfull] 然后,求反not_txdat_stall_d1: ~not_txdat_stall_d1 = ~[ (~txdat_sched_pend_v_dx & ~ram_pipe_fifo_pfull & ~ram_pipe_fifo_push) | ((~tmp_txdat_flit_v_d3 | ~ram_pipe_fifo_pfull) & ~ram_pipe_fifo_push) ] 使用德·摩根定律: ~(A | B) = ~A & ~B 其中 A = (~txdat_sched_pend_v_dx & ~ram_pipe_fifo_pfull & ~ram_pipe_fifo_push) B = ((~tmp_txdat_flit_v_d3 | ~ram_pipe_fifo_pfull) & ~ram_pipe_fifo_push) 所以: ~A = ~(~txdat_sched_pend_v_dx & ~ram_pipe_fifo_pfull & ~ram_pipe_fifo_push) = txdat_sched_pend_v_dx | ram_pipe_fifo_pfull | ram_pipe_fifo_push [因为 ~(X&Y&Z)=~X|~Y|~Z] ~B = ~[ (~tmp_txdat_flit_v_d3 | ~ram_pipe_fifo_pfull) & ~ram_pipe_fifo_push ] = ~(~tmp_txdat_flit_v_d3 | ~ram_pipe_fifo_pfull) | ram_pipe_fifo_push [因为 ~(X&Y)=~X|~Y] = (tmp_txdat_flit_v_d3 & ram_pipe_fifo_pfull) | ram_pipe_fifo_push [因为 ~(~A|~B)=A&B] 因此: ~not_txdat_stall_d1 = (txdat_sched_pend_v_dx | ram_pipe_fifo_pfull | ram_pipe_fifo_push) & [ (tmp_txdat_flit_v_d3 & ram_pipe_fifo_pfull) | ram_pipe_fifo_push ] 现在,block_txdat_sched_v_d2 = ~not_txdat_stall_d1 & ~not_txdat_stall_d2 = [ (txdat_sched_pend_v_dx | ram_pipe_fifo_pfull | ram_pipe_fifo_push) & ( (tmp_txdat_flit_v_d3 & ram_pipe_fifo_pfull) | ram_pipe_fifo_push ) ] & (tmp_txdat_flit_v_d3 & ram_pipe_fifo_pfull) 注意:最后还要与 ~not_txdat_stall_d2(即 tmp_txdat_flit_v_d3 & ram_pipe_fifo_pfull)进行与操作。 因此,我们可以写成: block_txdat_sched_v_d2 = (txdat_sched_pend_v_dx | ram_pipe_fifo_pfull | ram_pipe_fifo_push) & ( (tmp_txdat_flit_v_d3 & ram_pipe_fifo_pfull) | ram_pipe_fifo_push ) & (tmp_txdat_flit_v_d3 & ram_pipe_fifo_pfull) 现在,观察最后一项 (tmp_txdat_flit_v_d3 & ram_pipe_fifo_pfull) 与中间项中的 (tmp_txdat_flit_v_d3 & ram_pipe_fifo_pfull) 有重复,且中间项还有 ram_pipe_fifo_push 的部分。我们可以进行化简。 由于整个表达式是与关系,而且最后一项是 (tmp_txdat_flit_v_d3 & ram_pipe_fifo_pfull),那么中间项中与最后一项进行与操作时,中间项中的 ram_pipe_fifo_push 部分会被这个条件限制。 具体化简: 我们令 C = (tmp_txdat_flit_v_d3 & ram_pipe_fifo_pfull) 则表达式变为: block_txdat_sched_v_d2 = (txdat_sched_pend_v_dx | ram_pipe_fifo_pfull | ram_pipe_fifo_push) & ( C | ram_pipe_fifo_push ) & C 由于最后有一个&C,所以整个表达式只有在C为真时才可能为真。因此,我们可以将C提取出来: = C & (txdat_sched_pend_v_dx | ram_pipe_fifo_pfull | ram_pipe_fifo_push) & (C | ram_pipe_fifo_push) 因为C为真,所以 (C | ram_pipe_fifo_push) 一定为真(因为C已经为真)。因此,这一项可以去掉。 所以: block_txdat_sched_v_d2 = C & (txdat_sched_pend_v_dx | ram_pipe_fifo_pfull | ram_pipe_fifo_push) 但是,我们需要注意:当C为真时,(C | ram_pipe_fifo_push) 确实为真,所以可以省略。 因此: block_txdat_sched_v_d2 = (tmp_txdat_flit_v_d3 & ram_pipe_fifo_pfull) & (txdat_sched_pend_v_dx | ram_pipe_fifo_pfull | ram_pipe_fifo_push) 现在,我们观察括号内的三个条件:ram_pipe_fifo_pfull 已经出现在C中(即与C的ram_pipe_fifo_pfull相同),所以当C为真时,ram_pipe_fifo_pfull为真,那么括号内的 ram_pipe_fifo_pfull 这一项就为真,所以整个括号内的表达式必然为真(因为只要有一个为真即可)。 因此,当C为真时,括号内总是为真?不完全是,因为括号内是三个条件或,而ram_pipe_fifo_pfull为真(因为C要求它为真),所以整个或表达式为真。 所以: block_txdat_sched_v_d2 = tmp_txdat_flit_v_d3 & ram_pipe_fifo_pfull 但是,我们重审视一下:我们是否在化简过程中有错误? 让我们重检查: 原始代入后的表达式: block_txdat_sched_v_d2 = [ (txdat_sched_pend_v_dx | ram_pipe_fifo_pfull | ram_pipe_fifo_push) & ( (tmp_txdat_flit_v_d3 & ram_pipe_fifo_pfull) | ram_pipe_fifo_push ) ] & (tmp_txdat_flit_v_d3 & ram_pipe_fifo_pfull) 令 C = tmp_txdat_flit_v_d3 & ram_pipe_fifo_pfull 则: = [ (txdat_sched_pend_v_dx | ram_pipe_fifo_pfull | ram_pipe_fifo_push) & ( C | ram_pipe_fifo_push ) ] & C 由于C为真时,C|ram_pipe_fifo_push必然为真,所以中括号内的表达式简化为 (txdat_sched_pend_v_dx | ram_pipe_fifo_pfull | ram_pipe_fifo_push)。但是,当C为假时,整个表达式为假(因为最后有& C)。所以: = C & (txdat_sched_pend_v_dx | ram_pipe_fifo_pfull | ram_pipe_fifo_push) 现在,由于C中已经包含ram_pipe_fifo_pfull为真,所以括号中的ram_pipe_fifo_pfull为真,因此整个括号为真(无论其他两个条件如何)。所以: = C & 1 = C 因此,block_txdat_sched_v_d2 = tmp_txdat_flit_v_d3 & ram_pipe_fifo_pfull 但是,我们是否漏掉了什么?为什么原表达式会包含其他条件? 我们需要验证一下:在什么情况下block_txdat_sched_v_d2会为真? 根据原定义: block_txdat_sched_v_d2 = (~not_txdat_stall_d1 & ~not_txdat_stall_d2) 而not_txdat_stall_d1和not_txdat_stall_d2都是表示“不阻塞”的条件,所以block_txdat_sched_v_d2表示在两个“不阻塞”条件都不满足时,即两个都阻塞时才阻塞。 我们化简后得到 block_txdat_sched_v_d2 = tmp_txdat_flit_v_d3 & ram_pipe_fifo_pfull 这个结果意味着:只要同时满足tmp_txdat_flit_v_d3和ram_pipe_fifo_pfull,就会阻塞。 但是,我们需要验证这个化简是否与原始逻辑一致。 我们可以通过代入原始表达式来验证。 考虑一种情况:假设ram_pipe_fifo_pfull=1, tmp_txdat_flit_v_d3=1,那么根据化简结果,block_txdat_sched_v_d2=1。 现在计算原始的两个信号: not_txdat_stall_d2 = ~tmp_txdat_flit_v_d3 | ~ram_pipe_fifo_pfull = 0 | 0 = 0 not_txdat_stall_d1 = ... 其中一部分是 (~txdat_sched_pend_v_dx & ~ram_pipe_fifo_pfull & ~ram_pipe_fifo_push) -> 因为ram_pipe_fifo_pfull=1,所以这部分为0;另一部分是 (not_txdat_stall_d2 & ~ram_pipe_fifo_push) = (0 & ~ram_pipe_fifo_push) = 0。所以 not_txdat_stall_d1=0。 于是,~not_txdat_stall_d1=1, ~not_txdat_stall_d2=1,所以block_txdat_sched_v_d2=1,符合。 另一种情况:ram_pipe_fifo_pfull=0, tmp_txdat_flit_v_d3=1,则C=0,所以化简结果为0。 not_txdat_stall_d2 = ~1 | ~0 = 0 | 1 = 1 -> ~not_txdat_stall_d2=0 所以block_txdat_sched_v_d2= (~not_txdat_stall_d1 & 0) = 0,符合。 再考虑一种情况:ram_pipe_fifo_pfull=1, tmp_txdat_flit_v_d3=0,则C=0,结果为0。 not_txdat_stall_d2 = ~0 | ~1 = 1 | 0 = 1 -> ~not_txdat_stall_d2=0,所以结果为0。 再考虑一种情况:ram_pipe_fifo_pfull=0, tmp_txdat_flit_v_d3=0,则C=0,结果为0。 not_txdat_stall_d2 = ~0 | ~0 = 1 | 1 = 1 -> ~not_txdat_stall_d2=0,结果为0。 所以,当且仅当ram_pipe_fifo_pfull和tmp_txdat_flit_v_d3同时为1时,结果为1。 那么,为什么原始表达式中的其他变量(如txdat_sched_pend_v_dx, ram_pipe_fifo_push)没有影响?这是因为在化简过程中,我们利用了当C为真时,括号内的或表达式一定为真这个事实。也就是说,当C为真时,无论txdat_sched_pend_v_dx和ram_pipe_fifo_push取何值,括号内的表达式都为真。 因此,化简结果是正确的。 所以,我们可以直接写出: assign block_txdat_sched_v_d2 = tmp_txdat_flit_v_d3 & ram_pipe_fifo_pfull; 但是,我们不要忘记,在原始表达式中,not_txdat_stall_d1的定义里包含了not_txdat_stall_d2,而not_txdat_stall_d2又依赖于tmp_txdat_flit_v_d3和ram_pipe_fifo_pfull。经过代入化简后,最终只与这两个信号有关。 结论:替代后的表达式为: assign block_txdat_sched_v_d2 = tmp_txdat_flit_v_d3 & ram_pipe_fifo_pfull; 然而,我们需要确认:在原始表达式中,not_txdat_stall_d1的定义是否真的在代入后不影响结果?我们通过上面的真值表验证了四种情况,并且与化简结果一致。 因此,我们可以在代码中直接这样替换。 但是,请注意:原始表达式比较复杂,我们可能还需要考虑其他情况?例如,我们上面验证了当C为真时,无论其他信号如何,block_txdat_sched_v_d2都为真。而当C为假时,无论其他信号如何,block_txdat_sched_v_d2都为假。所以其他信号确实不影响结果。 所以,最终答案就是: assign block_txdat_sched_v_d2 = tmp_txdat_flit_v_d3 & ram_pipe_fifo_pfull; 但是,我们再看一下not_txdat_stall_d1的表达式: not_txdat_stall_d1 = (~txdat_sched_pend_v_dx & ~ram_pipe_fifo_pfull & ~ram_pipe_fifo_push) | (not_txdat_stall_d2 & ~ram_pipe_fifo_push); 当ram_pipe_fifo_pfull=1时,第一项的条件中~ram_pipe_fifo_pfull=0,所以第一项为0;第二项为 (not_txdat_stall_d2 & ~ram_pipe_fifo_push)。而not_txdat_stall_d2 = ~tmp_txdat_flit_v_d3 | ~ram_pipe_fifo_pfull = ~tmp_txdat_flit_v_d3 | 0 = ~tmp_txdat_flit_v_d3。 所以,not_txdat_stall_d1 = ~tmp_txdat_flit_v_d3 & ~ram_pipe_fifo_push。 那么,当ram_pipe_fifo_pfull=1且tmp_txdat_flit_v_d3=1时,not_txdat_stall_d1 = 0 & ~ram_pipe_fifo_push = 0。 而not_txdat_stall_d2 = 0(因为~tmp_txdat_flit_v_d3=0且~ram_pipe_fifo_pfull=0),所以~not_txdat_stall_d1=1,~not_txdat_stall_d2=1,所以block_txdat_sched_v_d2=1。 如果ram_pipe_fifo_pfull=1且tmp_txdat_flit_v_d3=0,那么not_txdat_stall_d2 = 1(因为~tmp_txdat_flit_v_d3=1),所以not_txdat_stall_d1 = 1 & ~ram_pipe_fifo_push(这里~ram_pipe_fifo_push的值会影响,但注意,即使~ram_pipe_fifo_push=0,那么not_txdat_stall_d1=0?不对,我们具体计算: not_txdat_stall_d1 = [0] | [ (1) & ~ram_pipe_fifo_push ] = ~ram_pipe_fifo_push 所以,如果ram_pipe_fifo_push=0,则not_txdat_stall_d1=1;如果ram_pipe_fifo_push=1,则not_txdat_stall_d1=0。 而~not_txdat_stall_d1:当ram_pipe_fifo_push=0时为0,当ram_pipe_fifo_push=1时为1。 ~not_txdat_stall_d2 = ~1 = 0。 所以block_txdat_sched_v_d2 = (0或1) & 0 = 0。 所以,当ram_pipe_fifo_pfull=1且tmp_txdat_flit_v_d3=0时,block_txdat_sched_v_d2=0,与我们的化简结果一致(因为C为0)。 因此,我们之前的结论正确。 所以,最终答案是: assign block_txdat_sched_v_d2 = tmp_txdat_flit_v_d3 & ram_pipe_fifo_pfull; 但是,我们重审视一下,为什么会出现这样的化简?实际上,原始表达式中的其他变量在满足C的条件时,不会影响结果。因此,我们可以安全地替换。 因此,在代码中,我们可以这样写: assign block_txdat_sched_v_d2 = tmp_txdat_flit_v_d3 & ram_pipe_fifo_pfull; 注意:这个结果依赖于具体的逻辑表达式,我们通过严格的代数和真值表验证了其正确性。 但是,如果原始表达式有多个条件相互影响,我们可能需要更仔细地分析。不过在此例中,化简是可行的。 </think> 根据给定的逻辑表达式进行代入和化简,结果如下: ### 步骤分析 1. **原始表达式**: ```verilog assign block_txdat_sched_v_d2 = (~not_txdat_stall_d1 & ~not_txdat_stall_d2); ``` 2. **代入表达式**: - `not_txdat_stall_d1 = (~txdat_sched_pend_v_dx & ~ram_pipe_fifo_pfull & ~ram_pipe_fifo_push) | (not_txdat_stall_d2 & ~ram_pipe_fifo_push);` - `not_txdat_stall_d2 = ~tmp_txdat_flit_v_d3 | ~ram_pipe_fifo_pfull;` 3. **化简过程**: - 先求 `~not_txdat_stall_d2`: ```verilog ~not_txdat_stall_d2 = ~(~tmp_txdat_flit_v_d3 | ~ram_pipe_fifo_pfull) = tmp_txdat_flit_v_d3 & ram_pipe_fifo_pfull; // 德·摩根定律 ``` - 再求 `~not_txdat_stall_d1`: ```verilog ~not_txdat_stall_d1 = ~[ (~txdat_sched_pend_v_dx & ~ram_pipe_fifo_pfull & ~ram_pipe_fifo_push) | (not_txdat_stall_d2 & ~ram_pipe_fifo_push) ] = (txdat_sched_pend_v_dx | ram_pipe_fifo_pfull | ram_pipe_fifo_push) & ~(not_txdat_stall_d2 & ~ram_pipe_fifo_push) // 德·摩根定律 = (txdat_sched_pend_v_dx | ram_pipe_fifo_pfull | ram_pipe_fifo_push) & (~not_txdat_stall_d2 | ram_pipe_fifo_push); ``` - 合并结果: ```verilog block_txdat_sched_v_d2 = ~not_txdat_stall_d1 & ~not_txdat_stall_d2 = [ (txdat_sched_pend_v_dx | ram_pipe_fifo_pfull | ram_pipe_fifo_push) & (~not_txdat_stall_d2 | ram_pipe_fifo_push) ] & (tmp_txdat_flit_v_d3 & ram_pipe_fifo_pfull); // 代入~not_txdat_stall_d2 ``` - **关键化简**: 由于 `tmp_txdat_flit_v_d3 & ram_pipe_fifo_pfull`(即 `~not_txdat_stall_d2`)为真时,`~not_txdat_stall_d2 | ram_pipe_fifo_push` 恒为真,因此: ```verilog block_txdat_sched_v_d2 = (tmp_txdat_flit_v_d3 & ram_pipe_fifo_pfull) & (txdat_sched_pend_v_dx | ram_pipe_fifo_pfull | ram_pipe_fifo_push) = tmp_txdat_flit_v_d3 & ram_pipe_fifo_pfull; // 当 ram_pipe_fifo_pfull=1 时括号内恒真 ``` ### 最终结果 ```verilog assign block_txdat_sched_v_d2 = tmp_txdat_flit_v_d3 & ram_pipe_fifo_pfull; ``` **说明**: - 化简后逻辑仅取决于 `tmp_txdat_flit_v_d3` 和 `ram_pipe_fifo_pfull` 两个信号。 - 当 FIFO 接近满(`ram_pipe_fifo_pfull=1`)且第 3 拍临时数据有效(`tmp_txdat_flit_v_d3=1`)时,阻塞调度信号生效。 - 其他变量(如 `txdat_sched_pend_v_dx`, `ram_pipe_fifo_push`)在化简过程中被消去,不影响最终结果[^1]。 --- ### 验证真值表 | `tmp_txdat_flit_v_d3` | `ram_pipe_fifo_pfull` | `block_txdat_sched_v_d2` | |-----------------------|------------------------|--------------------------| | 0 | 0 | 0 | | 0 | 1 | 0 | | 1 | 0 | 0 | | 1 | 1 | 1 |
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值