• BZOJ 1191: [HNOI2006]超级英雄Hero(二分图匹配)


    云神说他二分图匹配从来都是用网络流水过去的...我要发扬他的精神.. 这道题明显是二分图匹配.网络流的话可以二分答案+最大流.虽然跑得很慢....

    ----------------------------------------------------------------------------------------

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
      
    #define rep(i, n) for(int i = 0; i < n; ++i)
    #define clr(x, c) memset(x, c, sizeof(x))
    #define Rep(i, n) for(int i = 1; i <= n; ++i)
     
    using namespace std;
     
    const int maxn = 2000 + 5;
     
    struct edge {
    int to, cap;
    edge *next, *rev;
    };
     
    edge* pt;
    edge *head[maxn], *cur[maxn], *p[maxn];
    edge EDGE[maxn * maxn >> 1];
     
    void init() {
    pt = EDGE;
    clr(head, 0);
    }
     
    inline void add(int u, int v, int d) {
    pt->to = v;
    pt->cap = d;
    pt->next = head[u];
    head[u] = pt++;
    }
     
    inline void add_edge(int u, int v, int d) {
    add(u, v, d);
    add(v, u, 0);
    head[u]->rev = head[v];
    head[v]->rev = head[u];
    }
     
    int d[maxn], cnt[maxn];
    int S, T, N;
     
    const int inf = maxn;
     
    int maxFlow() {
    clr(cnt, 0);
    clr(d, 0);
    rep(i, N) cur[i] = head[i];
    cnt[0] = N;
    int flow = 0, x = S, A = inf;
    edge* e;
    while(d[S] < N) {
    for(e = cur[x]; e; e = e->next)
       if(d[e->to] + 1 == d[x] && e->cap > 0) break;
       
    if(e) {
    p[e->to] = cur[x] = e;
    x = e->to;
    A = min(A, e->cap);
    if(x == T) {
    flow += A;
    while(x != S) {
    p[x]->cap -= A;
    p[x]->rev->cap += A;
    x = p[x]->rev->to;
    }
    A = inf;
    }
    } else {
    if(!--cnt[d[x]]) break;
    d[x] = N;
    for(e = head[x]; e; e = e->next) if(d[e->to] + 1 < d[x] && e->cap > 0) {
    d[x] = d[e->to] + 1;
    cur[x] = e;
    }
    cnt[d[x]]++;
    if(x != S) x = p[x]->rev->to;
    }
    }
    return flow;
    }
     
    int V[maxn][2];
     
    int main() {
    int n, m;
    cin >> n >> m;
    Rep(i, m) scanf("%d%d", &V[i][0], &V[i][1]);
    int l = 0, r = min(n, m), ans;
    S = 0;
    while(l <= r) {
    int mid = (l + r) >> 1;
    N = mid + n + 2, T = N - 1;
    init();
    Rep(i, mid) add_edge(S, i, 1);
    Rep(i, n) add_edge(i + mid, T, 1);
    Rep(i, mid) 
       add_edge(i, mid + 1 + V[i][0], 1), add_edge(i, mid + 1 + V[i][1], 1);
    if(maxFlow() == mid) {
    ans = mid;
    l = mid + 1;
    } else
       r = mid - 1;
    }
    cout << ans << " ";
    return 0;
    }

      

    ----------------------------------------------------------------------------------------

    1191: [HNOI2006]超级英雄Hero

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 2353  Solved: 1111
    [Submit][Status][Discuss]

    Description

    现在电视台有一种节目叫做超级英雄,大概的流程就是每位选手到台上回答主持人的几个问题,然后根据回答问题的多少获得不同数目的奖品或奖金。主持人问题准备了若干道题目,只有当选手正确回答一道题后,才能进入下一题,否则就被淘汰。为了增加节目的趣味性并适当降低难度,主持人总提供给选手几个“锦囊妙计”,比如求助现场观众,或者去掉若干个错误答案(选择题)等等。 这里,我们把规则稍微改变一下。假设主持人总共有m道题,选手有n种不同的“锦囊妙计”。主持人规定,每道题都可以从两种“锦囊妙计”中选择一种,而每种“锦囊妙计”只能用一次。我们又假设一道题使用了它允许的锦囊妙计后,就一定能正确回答,顺利进入下一题。现在我来到了节目现场,可是我实在是太笨了,以至于一道题也不会做,每道题只好借助使用“锦囊妙计”来通过。如果我事先就知道了每道题能够使用哪两种“锦囊妙计”,那么你能告诉我怎样选择才能通过最多的题数吗?

    Input

    输入文件的一行是两个正整数n和m(0 < n <1001,0 < m < 1001)表示总共有n中“锦囊妙计”,编号为0~n-1,总共有m个问题。
    以下的m行,每行两个数,分别表示第m个问题可以使用的“锦囊妙计”的编号。
    注意,每种编号的“锦囊妙计”只能使用一次,同一个问题的两个“锦囊妙计”可能一样。

    Output

    第一行为最多能通过的题数p

    Sample Input

    5 6
    3 2
    2 0
    0 3
    0 4
    3 2
    3 2

    Sample Output

    4

    HINT

    Source

  • 相关阅读:
    数学工具WZgrapher
    零线和地线的区别,示波器如何测量市电?
    使用直流稳压电源时的注意事项!
    中文全角和半角输入有什么区别?
    ThinkingRock:使用方法
    2014记首
    如何使用Excel绘制甘特图
    AStyle代码格式工具在source insight中的使用
    STM32F103系列命名规则
    上市公司行情查询站点
  • 原文地址:https://www.cnblogs.com/JSZX11556/p/4523353.html
Copyright © 2020-2023  润新知