匹配的一些概念:
完美匹配、完备匹配、最佳匹配
交错轨
可增广轨
匈牙利算法原理:从当前匹配M出发,检查每个未盖点,然后从它出发寻找可增广路,找到可增广路,沿着增广路扩充,直到找不到这样的路停止。
JOJ 2730
题意:http://blog.csdn.net/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; }