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);
}