ZOJ3037 稳定婚姻问题
白书353页 挺有意思
//550ms
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<iomanip>
#include<queue>
using namespace std;
#define N 1010
int male_choice[N][N];
int female_rank[N][N];
int fwife[N],fhusb[N];
int next_girl[N];
queue<int>q;
void engage(int man,int woman)
{
if(fhusb[woman])
{
fwife[fhusb[woman]]=0;
q.push(fhusb[woman]);
}
fwife[man]=woman;
fhusb[woman]=man;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n;
scanf("%d",&n);
while(!q.empty())q.pop();
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
scanf("%d",&male_choice[i][j]);
}
q.push(i);
next_girl[i]=1;
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
int x;
scanf("%d",&x);
female_rank[i][x]=j;
}
}
memset(fwife,0,sizeof(fwife));
memset(fhusb,0,sizeof(fhusb));
while(!q.empty())
{
int man=q.front();q.pop();
int woman=male_choice[man][next_girl[man]++];
if(!fhusb[woman]){
engage(man,woman);
}
else if(female_rank[woman][man]<female_rank[woman][fhusb[woman]])
{
engage(man,woman);
}
else q.push(man);
}
for(int i=1;i<=n;i++)
{
printf("%d\n",fwife[i]);
}
}
}
二分图系统学习
http://blog.youkuaiyun.com/hackbuteer1/article/details/7398008
趣写算法系列之--匈牙利算法
http://blog.youkuaiyun.com/dark_scope/article/details/8880547
二分图模板:
模板一:匈牙利算法
POJ1469 500ms
#include<stdio.h>
#include<string>
#include<string.h>
#include<iostream>
using namespace std;
/* **************************************************************************
//二分图匹配(匈牙利算法的DFS实现)
//初始化:g[][]两边顶点的划分情况
//建立g[i][j]表示i->j的有向边就可以了,是左边向右边的匹配
//g没有边相连则初始化为0
//uN是匹配左边的顶点数,vN是匹配右边的顶点数
//调用:res=hungary();输出最大匹配数
//优点:适用于稠密图,DFS找增广路,实现简洁易于理解
//时间复杂度:O(VE)
//顶点编号从1开始的
//***************************************************************************/
const int MAXN=510;
int uN,vN;//u,v数目
int g[MAXN][MAXN];
int linker[MAXN];
bool used[MAXN];
bool dfs(int u)//从左边开始找增广路径
{
int v;
for(v=1;v<=vN;v++)//这个顶点编号从0开始,若要从1开始需要修改
if(g[u][v]&&!used[v])
{
used[v]=true;
if(linker[v]==-1||dfs(linker[v]))
{//找增广路,反向
linker[v]=u;
return true;
}
}
return false;//这个不要忘了,经常忘记这句
}
int hungary()
{
int res=0;
int u;
memset(linker,-1,sizeof(linker));
for(u=1;u<=uN;u++)//这个顶点编号从0开始,若要从1开始需要修改
{
memset(used,0,sizeof(used));
if(dfs(u)) res++;
}
return res;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
memset(g,0,sizeof(g));
scanf("%d%d",&uN,&vN);
for(int i=1;i<=uN;i++)
{
int k,x;
scanf("%d",&k);
while(k--)
{
scanf("%d",&x);
g[i][x]=1;
}
}
int ans=hungary();
if(ans==uN)printf("YES\n");
else printf("NO\n");
}
return 0;
}
最大独立集
求二分图的最大独立点集 , 用匈牙利算法先求出最大匹配数 , 然后用总数减去最大匹配数就是题目要求的答案 .邻接表写法:
zoj1137
#include<cstdio>
#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
#define N 550
#define INF 99999999
int n;
vector<int>g[N];
int linker[N];
bool used[N];
bool dfs(int u)
{
int v;
for(int i=0;i<g[u].size();i++)
{
v=g[u][i];
if(!used[v])
{
used[v]=true;
if(linker[v]==-1||dfs(linker[v]))
{
linker[v]=u;
return true;
}
}
}
return false;//这个不要忘了,经常忘记这句
}
int hungary()
{
int res=0;
memset(linker,-1,sizeof(linker));
for(int i=0;i<n;i++)
{
memset(used,0,sizeof(used));
if(dfs(i))res++;
}
return res;
}
int main()
{
while(~scanf("%d",&n))
{
for(int i=0;i<n;i++)g[i].clear();
for(int i=0;i<n;i++)
{
int a,k,b;
scanf("%d: (%d)",&a,&k);
while(k--)
{
scanf("%d",&b);
g[a].push_back(b);
}
}
int ans=hungary();
printf("%d\n",n-ans/2);
}
return 0;
}
模板二:Hopcroft-Carp算法
这个算法比匈牙利算法的时间复杂度要小,大数据可以采用这个算法
//poj_1469
/*==================================================*\
| 二分图匹配(Hopcroft-Carp 的算法)
| INIT: g[][]邻接矩阵;
| CALL: res = MaxMatch(); Nx, Ny要初始化!!!
| Mx,My为match
| 时间复杂度为O(V^0.5 E)
\*==================================================*/
/***********************Hopcroft-Carp 算法****************************************/
#include <cstdio>
#include <memory.h>
#include <queue>
using namespace std;
const int MAXN = 310;
const int INF = 1 << 28;
bool flag;
int p,n;
int Mx[MAXN], My[MAXN], Nx, Ny;
int dx[MAXN], dy[MAXN], dis;
bool vst[MAXN],g[110][310];
bool searchP(void)
{
queue <int> Q;
dis = INF;
memset(dx, -1, sizeof(dx));
memset(dy, -1, sizeof(dy));
for (int i = 1; i <= Nx; i++)
if (Mx[i] == -1){
Q.push(i); dx[i] = 0;
}
while (!Q.empty()) {
int u = Q.front(); Q.pop();
if (dx[u] > dis) break;
for (int v = 1; v <= Ny; v++)
if (g[u][v] && dy[v] == -1) {
dy[v] = dx[u]+1;
if (My[v] == -1) dis = dy[v];
else{
dx[My[v]] = dy[v]+1;
Q.push(My[v]);
}
}
}
return dis != INF;
}
bool DFS(int u){
for (int v = 1; v <= Ny; v++)
if (!vst[v] && g[u][v] && dy[v] == dx[u]+1) {
vst[v] = 1;
if (My[v] != -1 && dy[v] == dis) continue;
if (My[v] == -1 || DFS(My[v])) {
My[v] = u; Mx[u] = v;
return 1;
}
}
return 0;
}
int MaxMatch(void){
int res = 0;
memset(Mx, -1, sizeof(Mx));
memset(My, -1, sizeof(My));
while (searchP()) {
memset(vst, 0, sizeof(vst));
for (int i = 1; i <= Nx; i++)
if (Mx[i] == -1 && DFS(i)) res++;
}
return res;
}
/**********************************************************************/
int main()
{
int i,j,k,t,v,cnt;
scanf("%d",&t);
while (t--)
{
scanf("%d %d", &p, &n);
for (i = 1; i <= p; i++)
for (j = 1; j <= n; j++)
g[i][j] = false;
flag = true;
for (i = 1; i <= p; i++)
{
scanf("%d",&k);
if (k == 0)
flag = false;
while (k--)
{
scanf("%d",&v);
g[i][v] = true;
}
}
Nx = p; Ny = n;
if (flag)
{
cnt = MaxMatch();
if (cnt == p)
printf("YES\n");
else printf("NO\n");
}
else printf("NO\n");
}
return 0;
}