POJ 1274 / POJ 1469 / POJ 2239 二分图最大匹配

都是一些很裸的二分图最大匹配.

纯当复习了.


POJ 1274

#include<cstdio>
#include<cstring>
#include<vector>
#include<iostream>
using namespace std;
#define bug(s) cout<<#s<<"="<<s<<" "
inline int Rint() {int x; scanf("%d", &x); return x;}
#define MAXN 500
vector<int> G[MAXN];
int vis[MAXN];
int flag[MAXN];	//0-未盖	/ 对应点-已盖
int n, m;
int dfs(int u)
{
	for(int i=0; i<(int)G[u].size(); i++)
	{
		int v = G[u][i];
		if(!vis[v])	//未访问
		{
			vis[v] = 1;
			if(!flag[v] || dfs(flag[v]))	//!!不是dfs(v) -> dfs(flag[v]) 对应点
			{
				flag[v] = u;
				return 1;
			}
		}
	}
	return 0;
}
int hungary()
{
	memset(flag, 0, sizeof(flag));
	int ans=0;
	for(int i=1; i<=n; i++)	//集合X中点 1~m
	{
		memset(vis, 0, sizeof(vis));
		if(dfs(i)) ans++;
	}
	return ans;
}
void print_ans()	//输出匹配M
{
	for(int i=n+1; i<=n+n; i++)	//flag[v]=u...v=m+1~n
	if(flag[i])	//v为盖点,输出对应的匹配边
	{
		printf("%d->%d\n", flag[i], i);
	}
}
int main()
{
	while(scanf("%d%d", &n, &m)==2)
	{
		for(int i=1; i<=n; i++)
		{
			if(!G[i].empty()) G[i].clear();
		}
		for(int i=1; i<=n; i++)
		{
			//bug(i);
			int v;
			char ch;
			int cnt = Rint();
			while(cnt--)
			{
				v = Rint();
				//bug(v);
				G[i].push_back(v+n);
				//if(ch == '\n') break;
			}
			//cout<<endl;
		}
		printf("%d\n", hungary());
		//print_ans();
	}
	//read_graph();
	//printf("%d\n", hungary());
	//print_ans();
}

 POJ 1469

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<string>
#include<vector>
#include<map>
#include<algorithm>
using namespace std;
inline int Rint() { int x; scanf("%d", &x); return x; }
inline int max(int x, int y) { return (x>y)? x: y; }
inline int min(int x, int y) { return (x<y)? x: y; }
#define FOR(i, a, b) for(int i=(a); i<=(b); i++)
#define FORD(i,a,b) for(int i=(a);i>=(b);i--)
#define REP(x) for(int i=0; i<(x); i++)
typedef long long int64;
#define INF (1<<30)
#define bug(s) cout<<#s<<"="<<s<<" "

#define MAXN 400
#define MAXM MAXN*MAXN
//int G[MAXN][MAXN];	//{U}->{V}
int fa[MAXM], next[MAXM], u[MAXM], v[MAXM], w[MAXM], idx;	//边集数组前向星, 表头后面只能跟边, 因为若跟点无法确定下一个点信息
int flag[MAXN];	//盖, flag[{V}] = {U}
int vis[MAXN];	//dfs访问标记, 只对V
int n, m;

void addedge(int tu, int tv, int tw)
{
	u[idx] = tu; v[idx] = tv; w[idx] = tw; next[idx] = fa[tu]; fa[tu] = idx++;
}

int dfs(int tu)
{
	//vis[u] = 1;
	
	for(int e = fa[tu]; e!=-1; e = next[e])
	{
		int tv = v[e];
		if(vis[tv]) continue;
		vis[tv] = 1;
		if(!flag[tv] || dfs(flag[tv]))
		{
			//bug(v);bug(u)<<endl;
			flag[tv] = tu;
			return 1;
		}
	}
	return 0;
}

int hungry()
{
	int ans = 0;
	memset(flag, 0, sizeof(flag));		//清空盖点
	FOR(i, 1, n)		//每次从U出发, 找未盖的V点 or 增广路
	{
		memset(vis, 0, sizeof(vis));
		if(dfs(i)) ans++;
	}
	return ans;
}
int main()
{
	int T = Rint();
	while(T--)
	{
		scanf("%d%d", &n, &m);	// n门课, m个学生
		idx = 0;
		memset(fa, -1, sizeof(fa));
		//memset(G, 0, sizeof(G));
		FOR(i, 1, n)
		{
			int cnt = Rint();
			while(cnt--)
			{
				int tv = Rint();
				//G[i][v] = 1;
				addedge(i, tv, 1);
			}
		}
		printf("%s\n", hungry() == n? "YES": "NO");
	}
}

POJ 2239

这题只要把(星期, 班级)对, hash一下.就行

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<string>
#include<vector>
#include<map>
#include<algorithm>
using namespace std;
inline int Rint() { int x; scanf("%d", &x); return x; }
inline int max(int x, int y) { return (x>y)? x: y; }
inline int min(int x, int y) { return (x<y)? x: y; }
#define FOR(i, a, b) for(int i=(a); i<=(b); i++)
#define FORD(i,a,b) for(int i=(a);i>=(b);i--)
#define REP(x) for(int i=0; i<(x); i++)
typedef long long int64;
#define INF (1<<30)
#define bug(s) cout<<#s<<"="<<s<<" "

#define MAXN 1000
#define MAXM MAXN*MAXN
//int G[MAXN][MAXN];	//{U}->{V}
int fa[MAXM], next[MAXM], u[MAXM], v[MAXM], w[MAXM], idx;	//边集数组前向星, 表头后面只能跟边, 因为若跟点无法确定下一个点信息
int flag[MAXN];	//盖, flag[{V}] = {U}
int vis[MAXN];	//dfs访问标记, 只对V
int n, m;

void addedge(int tu, int tv, int tw)
{
	u[idx] = tu; v[idx] = tv; w[idx] = tw; next[idx] = fa[tu]; fa[tu] = idx++;
}

int dfs(int tu)
{
	//vis[u] = 1;
	
	for(int e = fa[tu]; e!=-1; e = next[e])
	{
		int tv = v[e];
		if(vis[tv]) continue;
		vis[tv] = 1;
		if(!flag[tv] || dfs(flag[tv]))
		{
			//bug(v);bug(u)<<endl;
			flag[tv] = tu;
			return 1;
		}
	}
	return 0;
}

int hungry()
{
	int ans = 0;
	memset(flag, 0, sizeof(flag));		//清空盖点
	FOR(i, 1, n)		//每次从U出发, 找未盖的V点 or 增广路
	{
		memset(vis, 0, sizeof(vis));
		if(dfs(i)) ans++;
	}
	return ans;
}
int main()
{
	//int T = Rint();
	while(scanf("%d", &n) == 1)	// n门课, m天
	{
		idx = 0;
		memset(fa, -1, sizeof(fa));
		//memset(G, 0, sizeof(G));
		FOR(i, 1, n)
		{
			int cnt = Rint();
			while(cnt--)
			{
				int tv = Rint();
				int cs = Rint();
				//G[i][v] = 1;
				//addedge(i, (tv-1)*7+cs, 1);
				addedge(i, (tv-1)*12+cs, 1);		// 把(天, 班级) 哈希即可.
			}
		}
		printf("%d\n", hungry());
	}
}


你可能感兴趣的:(POJ 1274 / POJ 1469 / POJ 2239 二分图最大匹配)