[bzoj5335][loj2574][TJOI2018]智力競賽【網絡流】

【題目鏈接】
  https://loj.ac/problem/2574
【題解】
  每次加入最小的點並判斷是否可行,判斷的方法是將每個點拆成入點和出點,加入時連一條下界爲1的邊,跑最小流。若最小流n+1 則可行。
  時間複雜度O(MV) (V)
【代碼】

# include <bits/stdc++.h>
# 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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章