P4589 [TJOI2018] 智力竞赛

P4589 [TJOI2018] 智力竞赛

小豆报名参加智力竞赛,他带上了 \(n\) 个好朋友作为亲友团一块来参加比赛。比赛规则如下:

一共有 \(m\) 道题目,每个人都有 \(1\) 次答题机会,每次答题为选择一道题目回答,在回答正确后,可以继续回答这个题目的后续题目,直到答错题目或者没有后续题目。

每个问题都会有一个价值,比赛最后参赛选手获得的奖励价值等价于该选手和他的亲友团没有回答的问题中的最低价值。

我们现在知道小豆和他的亲友团实力非常强,能够做出这次竞赛中的所有题目。

小豆想知道在知道题目和后续题目的条件下,他最大能获得的价值是多少?

输入格式

第一行有两个整数 \(n,m\)。(\(n\leq50,m\leq500\)

接下来 \(m\) 行,第 \(i+1\) 行表示编号为 \(i\) 的题目的题目信息,格式形如 \(v_i,k_i,a_{i,1},a_{i,2},...,a_{i,k_i}\),其中 \(v_i\) 表示该题目的价值,\(k_i\) 表示这个题目的后续题目个数,\(a_{i,1},a_{i,2},...,a_{i,k_i}\) 表示 \(k_i\) 个后续题目的编号。

输出格式

如果全部题目都能答对,则输出 AK,否则输出小豆可以获得的最高奖励价值。

说明/提示

对于 \(100\%\) 的数据,有 \(1<n\leq50,1<m\leq500,v_i\leq10^9,k_i,a_{i,j}\leq m\)

Solution:

题意本质上就是一张 DAG 上要我们求一个 最小可相交链覆盖。 我们转到二分图上来做的话,原问题就转化为了二分图上的最小路径覆盖,那么如何求解呢?

  • 我们想到二分图就很难不去想最大匹配,那么这题中,最大匹配的意义是什么呢?对于每个左侧的点,与之对应的匹配就是它所回答的下一道题目

  • 这样一来,原图上一段路径上,只有结尾处一个点是没有匹配的,对应一条路径,那么最小路径条数就是 \(N-match\)

同时还要注意一下,如果最小路径条数 \(need >n+1\) ,我们需要最大化“不在路径上的最小点权”

Code:

#include<bits/stdc++.h>
const int N=100005;
using namespace std;
struct Edge{
    int to,nxt;
}e[N<<2];
struct Node{
    int id,w;
}q[N];
bool cmp(Node n1,Node n2)
{
    return n1.w<n2.w;
}
int n,m,e_cnt,tim;
int head[N],in[N],vis[N],match[N];
void add(int x,int y)
{
    e[++e_cnt]={y,head[x]};
    head[x]=e_cnt;
}
bool dfs(int x)
{
    for(int i=head[x];i;i=e[i].nxt)
    {
        int to=e[i].to;
        if(vis[to]==tim)continue;vis[to]=tim;
        if(!match[to]||dfs(match[to]))
        {
            match[to]=x;
            return 1;
        }
    }
    return 0;
}
int main()
{
    //freopen("competition.in","r",stdin);
    //freopen("competition.out","w",stdout);
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        int k;
        scanf("%d%d",&q[i].w,&k);
        q[i].id=i;
        for(int j=1,x;j<=k;j++)
        {
            scanf("%d",&x);
            add(i,x+n);
        }
    }
    sort(q+1,q+1+m,cmp);
    int need=0;
    int u=1;
    for(;u<=m;u++)
    {
        tim++;
        need+=dfs(u)^1;
        if(need>n+1)break;
    }
    if(u==m+1)
    {
        cout<<"AK";
        return 0;
    }
    cout<<q[u].w;
    return 0;
}

posted @ 2025-06-28 17:20  liuboom  阅读(8)  评论(0)    收藏  举报