crf 的军训 (二分图匹配)

来源:互联网 发布:招募淘宝客网站 编辑:程序博客网 时间:2024/04/29 01:00

crf 的军训

9.3
思路:很像一道贪心的题目,好像贪心也能做,不过下面要介绍的是一种巧妙的方法——网络流(二分图)。
当a书满足x与y都比b书大时,a向b连边(一本书拆成两个点,二分图嘛),本来一本书一个书架,找二分图匹配的过程相当于就是把一本书(原来独占一个书架)并到其他书架上,就减少了一个书架。
最后用n-ans就好了。

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;const int N = 1000;const int M = 310;int n, ans=0, idc=0;int head[N];int link[N], vis[N];struct Book{    int x, y;}book[M];struct Edge{    int to, nxt;}ed[M * M];void adde(int u, int v){    ed[++idc].to = v;    ed[idc].nxt = head[u];    head[u] = idc;}int find(int u){    for(int k=head[u]; k; k=ed[k].nxt){        int v = ed[k].to;        if( !vis[v] ){            vis[v] = 1;            if(!link[v] || find(link[v])){                link[u] = v;                link[v] = u;                return 1;            }        }    }    return 0;}bool cmp(Book aa, Book bb){    if(aa.x == bb.x) return aa.y >= bb.y;    else return aa.x >= bb.x;}int main(){    freopen ("militarytraining.in", "r", stdin);    freopen ("militarytraining.out", "w", stdout);    scanf("%d", &n);    for(int i=1; i<=n; i++)        scanf("%d%d", &book[i].x, &book[i].y);    sort(book+1, book+n+1, cmp);    for(int i=1; i<n; i++){        for(int j=i+1; j<=n; j++){            if( book[i].y >= book[j].y ){                //adde(i+n, j); adde(j, i+n);                //printf("Y %d %d\n", i+n, j);                adde(i, j+n); adde(j+n, i);                //printf("Y %d %d\n", i, j+n);            }        }    }    //for(int i=1; i<=idc; i++)     for(int i=1; i<=2*n; i++){        memset(vis, 0, sizeof(vis));        if( !link[i] ) ans += find( i );//找到一本书可以并到一个书架里     }    printf("%d\n", n-ans);}