HDU 1150:
http://acm.hdu.edu.cn/showproblem.php?pid=1150
最小覆盖点 == 最大匹配数(选取最少的点数,使这些点和所有的边都有关联——把所有的边的覆盖)
两台机器,有n和m个工作模式,起始工作模式都为0,现在有k件工作,第i件工作可分别在两个机器上用各自的模式工作,但换模式要重启,问重启的最小次数。
写的时候因为是找二分最大匹配的题目时找到写的,想到了二分上去,也知道是求最小覆盖点 == 最大匹配数,但不是很能理解,先把代码写了再说。
写的时候注意起始模式是0,所以换模式时把0的排除再外。(因为这个原因错了很多次)
一:邻接阵做法
代码#include<iostream>using namespace std;int n,m,k;int map[105][105]; //记录X,Y对应点可否连接int vis[105]; //每次找增广路时对Y中点是否访问int dir[105]; //Y中点匹配的X中点的位置int find(int a){ int i; for(i=0;i<m;i++) { if(map[a][i]==1 && vis[i] == 0) { vis[i] = 1; if(dir[i] == -1 || find(dir[i])) { dir[i] = a; return 1; } } } return 0;}int main(){ int i,x,y; while(scanf("%d",&n)!=EOF && n!=0) { memset(map,0,sizeof(map)); memset(dir,-1,sizeof(dir)); scanf("%d%d",&m,&k); while(k--) { scanf("%d%d%d",&i,&x,&y); if(x && y) map[x][y] = 1; //应该不能再用map[y][x] = 1 } int sum = 0; for(i=0;i<n;i++) { memset(vis,0,sizeof(vis)); if(find(i)) sum++; } printf("%d\n",sum); } return 0;}
二:动态邻接表做法.
代码#include<iostream>using namespace std;int n,m,k;int vis[105]; //每次找增广路时对Y中点是否访问int dir[105]; //Y中点匹配的X中点的位置struct edge{ int from; int to; edge* next; edge() { from = to = 0; next = NULL; }};edge* List[105];void add_edge(int f,int t){ edge* node = new edge(); node->from = f; node->to = t; node->next = List[f]; List[f] = node;}int find(edge* node){ while(1) { if(node == NULL) { break; } int i = node->to; if(vis[i] == 0) { vis[i] = 1; if(dir[i] == -1 || find(List[dir[i]])) { dir[i] = node->from; return 1; } } node = node->next; } return 0;}int main(){ int i,x,y; while(scanf("%d",&n)!=EOF && n!=0) { for(i=0;i<=n;i++)//链表清空,一开始没清空,错了很多次 { List[i] = NULL; } memset(dir,-1,sizeof(dir)); scanf("%d%d",&m,&k); while(k--) { scanf("%d%d%d",&i,&x,&y); if(x && y) add_edge(x,y); } int sum = 0; for(i=1;i<=n;i++) { memset(vis,0,sizeof(vis)); if(find(List[i])) sum++; } printf("%d\n",sum); } return 0;}
HDU 1151:
http://acm.hdu.edu.cn/showproblem.php?pid=1151
最小路径覆盖(选取最少的边覆盖所有的点) == 节点数 - 最大匹配数
代码
#include <iostream>using namespace std;#define MAXN 125int vis[MAXN];int link[MAXN];int n,m;struct edge{ int from; int to; edge* next; edge() { from = to = 0; next = NULL; }};edge* List[MAXN];void add_edge(int f,int t){ edge* node = new edge(); node->from = f; node->to = t; node->next = List[f]; List[f] = node;}bool find(edge* node){ while(1) { if(node == NULL) break; int i = node->to; if(vis[i] == 0) { vis[i] = 1; if(link[i] == 0 || find(List[link[i]])) { link[i] = node->from; return 1; } } node = node->next; } return 0;}int main(){ int i; int t,x,y; scanf("%d",&t); while(t--) { memset(link,0,sizeof(link)); scanf("%d%d",&n,&m); for(i=0;i<=n;i++) { List[i] = NULL; } for(i=0;i<m;i++) { scanf("%d%d",&x,&y); add_edge(x,y); } int sum = 0; for(i=1;i<=n;i++) { memset(vis,0,sizeof(vis)); if(find(List[i])) sum++; } printf("%d\n",n-sum); } return 0;}
HDU 1068:
http://acm.hdu.edu.cn/showproblem.php?pid=1068
二分图最大独立集=顶点数-二分图最大匹配
代码
#include <iostream>using namespace std;const long max_edge = 100005;const long max_point = 1005;int n;int Index;struct node{ int y; int next;}stu[max_edge];int pre[max_point];//以该点为起点的第一条在stu中的存储位置int vis[max_point];//Y中结点的访问情况int link[max_point];//Y中与X中配对的情况void add_edge(int a,int b){ stu[Index].y = b; stu[Index].next = pre[a]; pre[a] = Index++;}void Init(){ int i,j,s,t,m; char c; Index = 1; memset(pre,-1,sizeof(pre)); memset(link,-1,sizeof(link)); for(i=0;i<n;i++) { cin>>s>>c>>c>>m>>c; for(j=0;j<m;j++) { scanf("%d",&t); add_edge(s,t); } }}bool find(int dir){ int i; for(i=pre[dir]; i!=-1; i=stu[i].next) { int ii = stu[i].y; if(vis[ii] == 0) { vis[ii] = 1; if(link[ii] == -1 || find(link[ii])) { link[ii] = dir; return true; } } } return false;}void Play(){ int i; int ans = 0; for(i=0;i<n;i++) { memset(vis,0,sizeof(vis)); if(find(i)) ans++; } printf("%d\n",n-ans/2);}int main(){ while(scanf("%d",&n)!=EOF) { Init(); Play(); } return 0;}
HDU 1281:
http://acm.hdu.edu.cn/showproblem.php?pid=1281
写的时候写搓了,一个小错误,find1递归的时候用了find函数,很是郁闷!
当数据量小的时候可以不用静态连接表存储,毕竟连接阵用起来比连接表方便!
代码#include <iostream>using namespace std;const long max_point = 1005;const long max_edge = 100005;int n,m,k;int cas = 0;int mat[max_point][max_point];int vis[max_point];int linky[max_point];int linkx[max_point];void Init(){ int i; int a,b; memset(mat,0,sizeof(mat)); for(i=0;i<k;i++) { scanf("%d%d",&a,&b); mat[a][b] = 1; }}bool find(int dir,bool flag){ int i; for(i=1;i<=m;i++) { if(mat[dir][i] && !vis[i]) { vis[i] = 1; if(linky[i]==-1 || find(linky[i],flag)) { if(flag) { linkx[dir] = i; linky[i] = dir; } return true; } } } return false;}bool can(){ int i; for(i=1;i<=n;i++) { if(linkx[i] == -1) { memset(vis,0,sizeof(vis)); if(find(i,0)) { return true; } } } return false;}void Play(){ int i,j; int ans = 0; memset(linkx,-1,sizeof(linkx)); memset(linky,-1,sizeof(linky)); for(i=1;i<=n;i++) { memset(vis,0,sizeof(vis)); if(find(i,1)) ans++; } int ans1 = 0; for(i=1;i<=n;i++) { if(linkx[i] != -1) { int tmp = linkx[i]; linkx[i] = -1; linky[tmp] = -1; mat[i][tmp] = 0; if(!can()) ans1++; mat[i][tmp] = 1; linky[tmp] = i; linkx[i] = tmp; } } printf("Board %d have %d important blanks for %d chessmen.\n",++cas,ans1,ans);}int main(){ while(scanf("%d%d%d",&n,&m,&k)!=EOF) { Init(); Play(); } return 0;}
HDU 1498:
http://acm.hdu.edu.cn/showproblem.php?pid=1498
感觉来了,这题没花什么精力,一杯咖啡的时候想了出来。对每个颜色,求最小点覆盖,如果大于k,则不能在k时间内完成,输出;否则可以完成。
代码#include <iostream>using namespace std;int n,k;const long max_color = 55;const long maxn = 105;int Hash[max_color];int map[max_color][maxn][maxn];int vis[maxn];int linkx[maxn],linky[maxn];void Init(){ int i,j; memset(map,0,sizeof(map)); memset(Hash,0,sizeof(Hash)); for(i=0;i<n;i++) { for(j=0;j<n;j++) { int color; scanf("%d",&color); map[color][i][j] = 1; Hash[color] = 1; } }}bool find(int dir,int u){ int i,j; for(i=0;i<n;i++) { if(1 == map[dir][u][i]) { if(0 == vis[i]) { vis[i] = 1; if(linky[i] == -1 || find(dir,linky[i])) { linky[i] = u; linkx[u] = i; return true; } } } } return false;}int MaxMatch(int dir){ int i; int sum = 0; memset(linkx,-1,sizeof(linkx)); memset(linky,-1,sizeof(linky)); for(i=0;i<n;i++) { if(-1 == linkx[i]) { memset(vis,0,sizeof(vis)); if(find(dir,i)) { sum++; } } } return sum;}void Play(){ int i; int flag = 0; for(i=1;i<=50;i++) {//对应每种颜色 if(1 == Hash[i]) { int num = MaxMatch(i); /*if(flag != 0) {//这个放在外面,PE了一次 printf(" "); }*/ if(num > k) { if(flag != 0) { printf(" "); } printf("%d",i); flag = 1; } } } if(0 == flag) { printf("-1"); } printf("\n");}int main(){ while(scanf("%d%d",&n,&k)!=EOF && (n!=0 || k!=0)) { Init(); Play(); } return 0;}
HDU 1528:
http://acm.hdu.edu.cn/showproblem.php?pid=1528
简单题,卡片为点,大小关系为边,求最大匹配。
代码#include <iostream>#include <map>using namespace std;const long maxn = 30;int k;map<char,int> M;int num_Adam[maxn],num_Eve[maxn];int linkx[maxn],linky[maxn];int mat[maxn][maxn],vis[maxn],pre[maxn];void Init(){ int i,j; char c1,c2; memset(mat,0,sizeof(mat)); M['2'] = 0;M['3'] = 1;M['4'] = 2;M['5'] = 3;M['6'] = 4; M['7'] = 5;M['8'] = 6;M['9'] = 7;M['T'] = 8;M['J'] = 9; M['Q'] = 10;M['K'] = 11;M['A'] = 12; M['H'] = 3;M['S'] = 2;M['D'] = 1;M['C'] = 0; scanf("%d",&k); for(i=0;i<k;i++) { cin>>c1>>c2; num_Adam[i] = M[c1] * 4 + M[c2]; } for(i=0;i<k;i++) { cin>>c1>>c2; num_Eve[i] = M[c1] * 4 + M[c2]; } for(i=0;i<k;i++) { for(j=0;j<k;j++) { if(num_Adam[i] < num_Eve[j]) { mat[i][j] = 1; } } }}bool find(int dir){ int i; for(i=0;i<k;i++) { if(1 == mat[dir][i] && 0 == vis[i]) { vis[i] = 1; if(linky[i] == -1 || find(linky[i])) { linky[i] = dir; linkx[dir] = i; return true; } } } return false;}void Play(){ int i; int ans = 0; memset(linkx,-1,sizeof(linkx)); memset(linky,-1,sizeof(linky)); for(i=0;i<k;i++) { if(-1 == linkx[i]) { memset(vis,0,sizeof(vis)); if(find(i)) ans++; } } printf("%d\n",ans);}int main(){ int t; scanf("%d",&t); while(t--) { Init(); Play(); } return 0;}
来源:https://www.cnblogs.com/silencExplode/archive/2010/12/04/1896036.html