匹配的一些概念:
完美匹配、完备匹配、最佳匹配
交错轨
可增广轨
匈牙利算法原理:从当前匹配M出发,检查每个未盖点,然后从它出发寻找可增广路,找到可增广路,沿着增广路扩充,直到找不到这样的路停止。
JOJ 2730
题意:http://blog.youkuaiyun.com/jxy859/article/details/6747413
邻接阵
#include <cstdio>
#include <cstring>
const int N=105;
const int M=105;
bool map[N][M];
//X Y
int match[M];
//Y中与X的哪个匹配,初始为N,表示没有匹配
int vis[N];
//表示X中的元素在dfs过程中是否被标记过
int n,m;
bool dfs (int u)
{
for (int i=0 ; i<n ; ++i)
if(map[u][i] && !vis[i])
{
vis[i]=true;
if(match[i]==-1 || dfs(match[i]))
{
match[i]=u;
return true;
}
}
return false;
}
int Maxmatch()
{
int res=0;
memset (match , -1 , sizeof(match));
for (int i=0 ; i<n ; ++i)
{
memset (vis , false , sizeof(vis));
if(dfs(i))res++;
}
return res++;
}
int k;
int sc[105][30];
bool valid (int x, int y)
{
for (int i=0 ; i<k ; ++i)
if(sc[x][i]>=sc[y][i])
return false ;
return true;
}
void build_graph()
{
memset (map , false , sizeof(map));
for (int i=0 ; i<n ; ++i)
{
for (int j=0 ; j<n ; ++j)
{
if(valid(i,j))map[i][j]=true;//有向边;
}
}
}
int main ()
{
int cas;
scanf("%d",&cas);
for (int I=1 ; I<=cas ; ++I)
{
scanf("%d%d",&n,&k);
for (int i=0 ; i<n ; ++i)
{
for (int j=0 ; j<k ; ++j)
scanf("%d",*(sc+i)+j);
}
build_graph();
int ans=Maxmatch();
printf("Case #%d: %d\n",I,n-ans);
}
return 0;
}
邻接表:
JOJ上已空间上的小优势 第一~~
#include <cstdio>
#include <cstring>
const int N=105;
const int M=105;
///实在摸不准 取max(N,M)做为上界;
const int maxe=10000;
int n,k;
struct Edge {
int v,next;
}edge[maxe];
int head[N],cnt;
void addedge (int u, int v)
{
edge[cnt].v=v;
edge[cnt].next=head[u];
head[u]=cnt++;
}
///
bool vis[N];
int match[M];
bool dfs (int u)
{
for (int p=head[u] ; ~p ; p=edge[p].next)
{
int v=edge[p].v;
if(vis[v])continue;
vis[v]=true;
if(match[v]==-1 || dfs(match[v]))
{
match[v]=u;
return true;
}
}
return false;
}
int Maxmatch()
{
int res=0;
memset (match , -1 , sizeof(match));
for (int i=0 ; i<n ; ++i)
{
memset (vis , 0 , sizeof(vis));
if(dfs(i))++res;
}
return res;
}
int stock[M][30];
bool valid (int a, int b)
{
for (int i=0 ; i<k ; ++i)
if(stock[a][i]>=stock[b][i])return false ;
return true;
}
void build_graph()
{
memset (head , -1 , sizeof(head));
cnt=0;
for (int i=0 ; i<n ; ++i)
{
for (int j=0 ; j<n ; ++j)
{
if(valid (i,j))addedge (i,j);
}
}
}
int main ()
{
int cas;
scanf("%d",&cas);
for (int I=1 ; I<=cas ; ++I)
{
scanf("%d%d",&n,&k);
for (int i=0 ; i<n ; ++i)
{
for (int j=0 ; j<k ; ++j)
{
scanf("%d",*(stock+i)+j);
}
}
build_graph();
printf("Case #%d: %d\n",I,n-Maxmatch());
///求最小路径覆盖时尤其要注意n
}
return 0;
}
HDOJ 3991 Harry Potter and the Present II
给出一个无向图,给出p个要求,问至少再需要多少个伙伴才能完成所有的要求。
显然最小路径覆盖。
这题时间卡的很紧,构造网络流会超时,只好现学的匈牙利,1200+MS过的,囧。
#include <cstdio>
#include <cstring>
#define min(a,b) (a<b?a:b)
using namespace std;
const int N=1005;
const int M=1005;
///实在摸不准 取max(N,M)做为上界;
const int maxe=30000000;
const int maxn=2100;
const int inf=0x3fffffff;
const long long Inf=20000000000000ll;
int n,k;
struct Edge {
int v,next;
}edge[maxe];
int head[N],cnt;
void addedge (int u, int v)
{
edge[cnt].v=v;
edge[cnt].next=head[u];
head[u]=cnt++;
}
///
bool vis[N];
int match[M];
bool dfs (int u)
{
for (int p=head[u] ; ~p ; p=edge[p].next)
{
int v=edge[p].v;
if(vis[v])continue;
vis[v]=true;
if(match[v]==-1 || dfs(match[v]))
{
match[v]=u;
return true;
}
}
return false;
}
int Maxmatch(int nodes)
{
int res=0;
memset (match , -1 , sizeof(match));
for (int i=0 ; i<nodes ; ++i)
{
memset (vis , 0 , sizeof(vis));
if(dfs(i))++res;
}
return res;
}
///
long long map[N][N];
int q,m;
long long qt[1005];
int qp[1005];
void build_graph()//o(n*n*k)
{
memset (head , -1 , sizeof(head));
cnt=0;
for (int k=0 ; k<n ; ++k)
{
for (int i=0 ; i<n ; ++i)
{
for (int j=0 ; j<n ; ++j)
{
if(map[i][k]!=Inf && map[k][j]!=Inf &&
map[i][j]>map[i][k]+map[k][j])
map[i][j]=map[i][k]+map[k][j];
}
}
}
/*for (int i=0 ; i<n ; ++i)
{
for (int j=0 ; j<n ; ++j)
printf("%d-",map[i][j]);
printf("\n");
}*/
///处理最短路
for (int i=0 ; i<q ; ++i)
{
for (int j=0 ; j<q ; ++j)
{
if(i==j)continue;
//if(qp[i]==qp[j] && qt[i]<=qt[j]) addedge(i , j);
if(map[qp[j]][qp[i]]<=qt[j]-qt[i])
addedge (i , j);
}
}
///构图
}
int main ()
{
int u,v,w;
int cas;
scanf("%d",&cas);
for (int I=1 ; I<=cas ; ++I)
{
scanf("%d%d%d",&n,&m,&q);
for (int i=0 ; i<n ; ++i)
for (int j=0 ; j<n ; ++j)
{
if(i!=j)map[i][j]=Inf;
else map[i][i]=0;
}
for (int i=0 ; i<m ; ++i)
{
scanf("%d%d%d",&u,&v,&w);
map[u][v]=map[v][u]=min(map[u][v] , w);//重边?
}
for (int i=0 ; i<q ; ++i)
{
scanf("%d%d",qp+i,qt+i);
}
build_graph();
printf("Case %d: %d\n",I,q-Maxmatch(q)-1);
}
return 0;
}