码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2015-05-22 23:45:00      阅读:152      评论:0      收藏:0      [点我收藏+]

标签:

技术分享

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

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

#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 << "\n";
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

 

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

标签:

原文地址:http://www.cnblogs.com/JSZX11556/p/4523353.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!