题意:有M个女生,N个男生,他们要玩过山车又必须是一男一女一起,女生只愿意和她心中的几位男生坐在一起,问最多能匹配多少对。
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2063
——>>刚学了一个二分图的匈牙利算法,但那是一个无向图,编号从1到最后,而题中的是女N人,男M人,编号分别从1开始,这就纳闷了,于是试下将男生编号全部加上女生人数得到男生新编号,没料到不但没TLE,还0ms过,壮哉!
#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;
const int maxn = 1000 + 10;
vector<int> G[maxn];
bool vis[maxn];
int fa[maxn];
bool dfs(int u)
{
int d = G[u].size();
for(int i = 0; i < d; i++)
{
int v = G[u][i];
if(!vis[v])
{
vis[v] = 1;
int temp = fa[v];
fa[v] = u;
if(temp == -1 || dfs(temp)) return 1;
fa[v] = temp;
}
}
return 0;
}
int main()
{
int K, M, N, i, u, v;
while(~scanf("%d", &K))
{
if(!K) return 0;
for(i = 0; i < maxn; i++) G[i].clear();
scanf("%d%d", &M, &N);
int n = M + N;
for(i = 0; i < K; i++)
{
scanf("%d%d", &u, &v);
G[u].push_back(v + M);
G[v + M].push_back(u);
}
memset(fa, -1, sizeof(fa));
for(i = 1; i <= n; i++)
{
memset(vis, 0, sizeof(vis));
dfs(i);
}
int cnt = 0;
for(i = 1; i <= n; i++) if(fa[i] != -1) cnt++;
printf("%d\n", cnt/2);
}
return 0;
}
也用Java写了个,但运行时间多了好多,171ms:
import java.util.Scanner;
public class Main {
static final int maxn = 1000 + 10;
static boolean G[][] = new boolean[maxn][maxn], vis[] = new boolean[maxn];
static int fa[] = new int[maxn], n;
public static boolean dfs(int u){
for(int i = 1; i <= n; i++) if(G[u][i] == true && vis[i] == false){
vis[i] = true;
int temp = fa[i];
fa[i] = u;
if(temp == -1 || dfs(temp) == true) return true;
fa[i] = temp;
}
return false;
}
public static void main(String[] args) {
int K, M, N, i, j;
Scanner cin = new Scanner(System.in);
while(cin.hasNextInt()){
K = cin.nextInt();
if(K == 0) break;
M = cin.nextInt();
N = cin.nextInt();
n = M + N;
for(i = 1; i <= n; i++)
for(j = 1; j <= n; j++)
G[i][j] = false;
for(i = 0; i < K; i++){
int u = cin.nextInt();
int v = cin.nextInt();
G[u][v+M] = true;
G[v+M][u] = true;
}
for(i = 1; i <= n; i++) fa[i] = -1;
for(i = 1; i <= n; i++){
for(j = 1; j <= n; j++) vis[j] = false;
dfs(i);
}
int cnt = 0;
for(i = 1; i <= n; i++) if(fa[i] != -1) cnt++;
System.out.println(cnt/2);
}
cin.close();
}
}
2014.5.10,再来(1228KB内存,0MS):
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 500 + 10;
bool S[maxn], T[maxn];
int M, N, w[maxn][maxn], left[maxn];
bool match(int x) {
S[x] = true;
for(int i = 1; i <= N; i++) if(w[x][i] && !T[i]) {
T[i] = true;
if(!left[i] || match(left[i])) {
left[i] = x;
return true;
}
}
return false;
}
int main()
{
int K, G, B;
while(scanf("%d", &K) && K) {
scanf("%d%d", &M, &N);
memset(w, 0, sizeof(w));
for(int i = 0; i < K; i++) {
scanf("%d%d", &G, &B);
w[G][B] = 1;
}
memset(left, 0, sizeof(left));
for(int i = 1; i <= M; i++) {
memset(S, 0, sizeof(S));
memset(T, 0, sizeof(T));
match(i);
}
int cnt = 0;
for(int i = 1; i <= N; i++)
if(left[i])
cnt++;
printf("%d\n", cnt);
}
return 0;
}
再来(224KB内存,0MS):
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 500 + 10;
bool S[maxn], T[maxn];
int M, N, left[maxn];
int hed[maxn<<1], nxt[maxn<<1], v[maxn<<1], ecnt;
void init() {
memset(hed, -1, sizeof(hed));
ecnt = 0;
}
void add_edge(int uu, int vv) {
v[ecnt] = vv;
nxt[ecnt] = hed[uu];
hed[uu] = ecnt++;
}
bool match(int x) {
S[x] = true;
for(int e = hed[x]; e != -1; e = nxt[e]) {
int to = v[e];
if(!T[to]) {
T[to] = true;
if(!left[to] || match(left[to])) {
left[to] = x;
return true;
}
}
}
return false;
}
int main()
{
int K, G, B;
while(scanf("%d", &K) && K) {
scanf("%d%d", &M, &N);
init();
for(int i = 0; i < K; i++) {
scanf("%d%d", &G, &B);
add_edge(G, B);
}
memset(left, 0, sizeof(left));
for(int i = 1; i <= M; i++) {
memset(S, 0, sizeof(S));
memset(T, 0, sizeof(T));
match(i);
}
int cnt = 0;
for(int i = 1; i <= N; i++)
if(left[i])
cnt++;
printf("%d\n", cnt);
}
return 0;
}