The Perfect Stall_poj1274_匹配

本文介绍了一个基于二分图最大匹配的实际问题:如何最优地分配奶牛到不同的牛棚以最大化产奶量。通过使用匈牙利算法实现了一种有效的解决方案,并提供了完整的C++代码示例。

Description

Farmer John completed his new barn just last week, complete with all the latest milking technology. Unfortunately, due to engineering problems, all the stalls in the new barn are different. For the first week, Farmer John randomly assigned cows to stalls, but it quickly became clear that any given cow was only willing to produce milk in certain stalls. For the last week, Farmer John has been collecting data on which cows are willing to produce milk in which stalls. A stall may be only assigned to one cow, and, of course, a cow may be only assigned to one stall.
Given the preferences of the cows, compute the maximum number of milk-producing assignments of cows to stalls that is possible.

Input

The input includes several cases. For each case, the first line contains two integers, N (0 <= N <= 200) and M (0 <= M <= 200). N is the number of cows that Farmer John has and M is the number of stalls in the new barn. Each of the following N lines corresponds to a single cow. The first integer (Si) on the line is the number of stalls that the cow is willing to produce milk in (0 <= Si <= M). The subsequent Si integers on that line are the stalls in which that cow is willing to produce milk. The stall numbers will be integers in the range (1..M), and no stall will be listed twice for a given cow.

Output

For each case, output a single line with a single integer, the maximum number of milk-producing stall assignments that can be made.

Source

USACO 40

Analysis

二分图的最大匹配,c++的vector不会用只好套fp的邻接表模板惹(哭泣)

匈牙利算法,话说为什么poj题目这么多要用eof被坑惨

Code

#include <stdio.h>
#include <cstring>
using namespace std;
struct edge
{
    int x,y,next;
};

edge e[40001];

bool v[201];

int n,k,ans=0,maxE=0;
int link[201],ls[40001];

void add(int x,int y)
{
    e[++maxE].x=x;
    e[maxE].y=y;
    e[maxE].next=ls[x];
    ls[x]=maxE;
}
bool find(int x)
{
    for (int i=ls[x];i;i=e[i].next)
        if (!v[e[i].y])
        {
            int p=link[e[i].y];
            link[e[i].y]=x;
            v[e[i].y]=true;
            if (!p||find(p))
                return true;
            link[e[i].y]=p;
        }
    return false;
}
int main()
{   
    while(scanf("%d%d",&n,&k)!=EOF)
    {
        maxE=0;
        ans=0;
        memset(ls,0,sizeof(ls));
        memset(link,0,sizeof(link));
        for (int i=1;i<=n;i++)
        {
            int x,y;
            scanf("%d",&x);
            for (int j=1;j<=x;j++)
            {
                scanf("%d",&y);
                add(i,y);
            }
        }
        for (int i=1;i<=n;i++)
        {
            memset(v,false,sizeof(v));
            if (find(i)) 
                ans++;
        }

        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 |
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值