http://poj.org/problem?id=1947
题意:
给一个n*n矩阵,里面有k个障碍,(n<=500,k<=10000)
每次操作去掉一行/或一列的障碍物,要求最少操作数使得所有的障碍消失
。。。把矩阵的每行和每列都看成一个点,然后对一个在x行y列的障碍,就看成一条连接x和y的边。
那么每次删除一行或一列的操作,就对应选择一个点,而与这个点相连的所有边都会被kill掉
这也就达到我们删除一行/列的目的了
那么题目就变成选择最少的点,使得图中所有的边都被覆盖了(也就是所有的障碍都得以kill)
也就是求 最小点覆盖数 ,在二分图里,它等于最大匹配数
匈牙利算法
邻接矩阵:
#include <cstdio> #include <cmath> #include <cstring> #include <string> #include <algorithm> #include <queue> #include <map> #include <set> #include <vector> #include <iostream> using namespace std; const double pi=acos(-1.0); double eps=0.000001; //顶点编号从0开始的 const int MAXN = 510; int uN,vN;//u,v的数目,使用前面必须赋值 int g[MAXN][MAXN];//邻接矩阵 int linker[MAXN]; bool used[MAXN]; bool dfs(int u) { for(int v = 0; v < vN;v++) 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; memset(linker,-1,sizeof(linker)); for(int u = 0;u < uN;u++) { memset(used,false,sizeof(used)); if(dfs(u))res++; } return res; } int main() { int i,j,k; cin>>uN; vN=uN; cin>>k; int x,y; memset( g, 0, sizeof (g)); for (i=0;i<k;i++) { scanf("%d%d",&x,&y); g[x-1][y-1] =1; } int ret=hungary(); printf("%d\n",ret); return 0; }
#include <cstdio> #include <cmath> #include <cstring> #include <string> #include <algorithm> #include <queue> #include <map> #include <set> #include <vector> #include <iostream> using namespace std; const double pi=acos(-1.0); double eps=0.000001; const int MAXN = 5010;//点数的最大值 const int MAXM = 50010;//边数的最大值 struct Edge { int to,next; }edge[MAXM]; int head[MAXN],tot; void init() { tot = 0; memset(head,-1,sizeof(head)); } void addedge(int u,int v) { edge[tot].to = v; edge[tot].next = head[u]; head[u] = tot++; } int linker[MAXN]; bool used[MAXN]; int uN; bool dfs(int u) { for(int i = head[u]; i != -1 ;i = edge[i].next) { int v = edge[i].to; 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 u = 0; u < uN;u++)//点的编号0~uN-1 { memset(used,false,sizeof(used)); if(dfs(u))res++; } return res; } int main() { init(); int i,j,k; cin>>uN; cin>>k; int x,y; for (i=0;i<k;i++) { scanf("%d%d",&x,&y); addedge(x-1,y-1); } int ret=hungary(); printf("%d\n",ret); return 0; }