Time Limit: 10 Sec Memory Limit: 256 MB
Description
小豆报名参加智力竞赛,他带上了n个好朋友作为亲友团一块来参加比赛。
比赛规则如下:
一共有m道题目,每个入都有1次答题机会,每次答题为选择一道题目回答,在回答正确后,可以从这个题目的后续题目,直达题目答错题目或者没有后续题目。每个问题都会代表一个价值,比赛最后的参赛选手获得奖励价值等价于该选手和他的亲友团没有回答的问题中的最低价值。我们现在知道小豆和他的亲友团实力非常强,能够做出这次竞赛中的所有题目。
小豆想知道在知道题目和后续题目的条件下,他最大能获得价值是多少?
Input
第一行有两个整数n, m。(n ≤ 50, m ≤ 500)
接下来m行,第i+1行表示编号为i的题目的题目信息;
格式如下vi, ki, ai_1, ai_2, …, ai_ki 。
其中vi表示该题目的价值,ki 表示这个题目的后续,
ai_1, ai_2, …, ai_ki 表示这i 个题目的后续题目编号。
1 < n ≤ 50, 1 < m ≤ 500, vi ≤ 10^9, ki, ai_j ≤ m。
Output
如果全部题目都能答对,这输出“AK”,否则输出小豆可以获得的最高奖励价值。
题目分析
假如只考虑能不能全部答对,那么这题显然就是求DAG最小链覆盖
原图传递闭包后二分图匹配,若m-匹配数<=n+1则可以AK
如果不能AK,可以二分mid为没答出来的最小分值
检查是否可以把分值小于mid的所有题都答出来
即只保留原图分值小于mid的结点再做DAG最小链覆盖
一开始匹配写的网络流愉快地T飞了
#include<iostream>
#include<vector>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cstdio>
using namespace std;
typedef long long lt;
int read()
{
int f=1,x=0;
char ss=getchar();
while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
return f*x;
}
const int inf=2e9;
const int maxn=1010;
int n,m;
int val[maxn],mx;
int mp[maxn][maxn],edge[maxn][maxn];
int match[maxn],vis[maxn];
int dfs(int u)
{
for(int v=1;v<=m;v++)
{
if(!mp[u][v]||vis[v]) continue;
vis[v]=1;
if(!match[v]||dfs(match[v]))
{
match[v]=u;
return 1;
}
}
return 0;
}
int work(int x)
{
int res=0;
memset(match,0,sizeof(match));
for(int i=1;i<=m;i++)
{
if(val[i]>=x) continue;
memset(vis,0,sizeof(vis));
if(dfs(i)) res++;
}
return res;
}
void build(int x)
{
for(int i=1;i<=m;++i)
for(int j=1;j<=m;++j)
if(val[i]<x&&val[j]<x&&i!=j) mp[i][j]=edge[i][j];
else mp[i][j]=0;
}
int check(int x)
{
build(x); int cnt=0;
for(int i=1;i<=m;++i) if(val[i]<x) cnt++;
if(cnt-work(x)<=n+1) return 1;
else return 0;
}
int main()
{
n=read();m=read();
for(int i=1;i<=m;++i)
{
val[i]=read(); mx=max(mx,val[i]);
int k=read(); edge[i][i]=1;
while(k--) edge[i][read()]=1;
}
for(int k=1;k<=m;++k)
for(int x=1;x<=m;++x)
for(int y=1;y<=m;++y)
edge[x][y]|=edge[x][k]&edge[k][y];
build(inf);
if(m-work(inf)<=n+1) printf("AK");
else
{
int L=0,R=mx,ans=0;
while(L<R)
{
int mid=L+R>>1;
if(check(mid)) L=mid+1,ans=mid;
else R=mid;
}
printf("%d\n",ans);
}
return 0;
}