【题目链接】
https://loj.ac/problem/2574
【题解】
每次加入最小的点并判断是否可行,判断的方法是将每个点拆成入点和出点,加入时连一条下界为1的边,跑最小流。若最小流 ≤n+1 ≤ n + 1 则可行。
时间复杂度 O(MV) O ( M V ) (V为边数) ( V 为 边 数 )
【代码】
# include
# define ll long long
# define inf 0x3f3f3f3f
# define N 1010
# define M 1000010
using namespace std;
int read(){
int tmp = 0, fh = 1; char ch = getchar();
while (ch < '0' || ch > '9') {if (ch == '-') fh = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9'){tmp = tmp * 10 + ch - '0'; ch = getchar(); }
return tmp * fh;
}
struct Edge{
int data, next, re, l;
}e[M];
int head[N], cur[N], dis[N], q[N], place, m, n, in[N], out[N], v[N], num[N], vote[N], p[N];
vector <int> eg[N];
void build(int u, int v, int l){
e[++place].data = v; e[place].next = head[u]; head[u] = place; e[place].l = l; e[place].re = place + 1;
e[++place].data = u; e[place].next = head[v]; head[v] = place; e[place].l = 0; e[place].re = place - 1;
}
void bfs(int S, int T){
memset(dis, inf, sizeof(dis));
dis[S] = 0; int pl = 1, pr = 1; q[1] = S;
while (pl <= pr && dis[T] == inf){
int x = q[pl++];
for (int ed = head[x]; ed != 0; ed = e[ed].next)
if (dis[e[ed].data]==inf && e[ed].l > 0){
dis[e[ed].data] = dis[x] + 1,
q[++pr] = e[ed].data;
if (q[pr] == T) return;
}
}
}
int dfs(int x, int l, int T){
if (x == T) return l;
int sum = 0;
for (int ed = cur[x]; ed != 0; ed = e[ed].next)
if (dis[e[ed].data] == dis[x] + 1 && e[ed].l > 0){
int f = dfs(e[ed].data, min(e[ed].l, l), T);
sum = sum + f, l = l - f;
e[ed].l -= f; e[e[ed].re].l += f;
if (l == 0){
cur[x] = ed;
return sum;
}
}
cur[x] = 0;
return sum;
}
int dinic(int S, int T, int l){
int sum = 0;
for (bfs(S, T); dis[T] != inf && l; bfs(S, T)){
memcpy(cur, head, sizeof(cur));
int tmp = dfs(S, l, T);
sum += tmp; l -= tmp;
}
return sum;
}
bool cmp(int x, int y){
return v[x] < v[y];
}
int main(){
m = read(), n = read();
for (int i = 1; i <= n; i++){
v[i] = read(); num[i] = read();
vote[i] = v[i]; p[i] = i;
for (int j = 1; j <= num[i]; j++)
eg[i].push_back(read());
}
m++;
int S = 2 * n + 1, T = 2 * n + 2, SS = 2 * n + 3, TT = 2 * n + 4, ans = n, cnt = 0;
sort(vote + 1, vote + n + 1);
sort(p + 1, p + n + 1, cmp);
for (int i = 1; i <= n; i++)
in[i] = i, out[i] = i + n;
for (int i = 1; i <= n; i++)
build(in[i], out[i], inf);
for (int i = 1; i <= n; i++)
for (int j = 0; j < num[i]; j++)
build(out[i], in[eg[i][j]], inf);
for (int i = 1; i <= n; i++)
build(S, in[i], inf), build(out[i], T, inf);
for (int i = 1; i <= n; i++){
build(SS, out[p[i]], 1);
build(in[p[i]], TT, 1);
cnt += dinic(SS, TT, inf);
if (i - cnt > m){
ans = i - 1;
break;
}
}
if (ans == n)
printf("AK\n");
else printf("%d\n", vote[ans + 1]);
return 0;
}