快顶不住了,理解了多少,先写出来再说;
题意:
军队里面要展开实战演练,已经将n个士兵分成了两队,红队和蓝队。指挥官认为,如果两个属于不同阵营中的士兵是好朋友,那么演练就会有感情因素的干扰。所以要选出最少的人,以排除感情因素的干扰。问要选出多少人?选哪些人?
分析: 就题目而已,很明显是一道求最小覆盖点集的题目,又最小覆盖点数==最大匹配数,所以,单求出队人数的话,就是一道完完全全的求二分最大匹配的题目,可是,要怎么求出最小覆盖点集呢?而且还要按字典序输出?问题就在这里了,在求出最大匹配数的基础,从第一个点开始枚举,若去掉这个点,此时,最小覆盖数减少(即从该点匹配的点为起点,找不到增广路径),则该点属于最小覆盖点集,应该输出,且去掉,否则,恢复该点,继续枚举;
因为从第一个点开始枚举,所以保证了字典序输出。
整个算法的过程还不算是理解了,因为有一个坎一直过不去,是我对寻找增广路径的过程还理解的不够透彻吗?当然枚举到一个点时,匹配的点已经删掉了,这时候若调用深搜,返回值肯定为假,即找不到增广路,这时候该点不是要输出了吗?可是有没有加一个判断都过了,是代码在处理的时候已经考虑了这种情况了吗?还是根本不会出现这种情况?求大牛解释
#include<iostream> using namespace std; int wet[205][205]; int mx[205], my[205]; char vstd[205]; char del[205]; //是否属于最小点覆盖集 int grp[205]; //0, 1 int nv, ne; int pathx(int x) { int y; if(del[x]) return 0; //如果该点属于最小点覆盖集,就不用再找了. for(y = 1; y <= nv; y++) { if(wet[x][y] && !vstd[y] && !del[y]) { vstd[y] = 1; if(my[y]==-1 || pathx(my[y])) { my[y] = x; mx[x] = y; return 1; } } } return 0; } int pathy(int y) { int x; if(del[y]) return 0; for(x = 1; x <= nv; x++) { if(wet[x][y] && !vstd[x] && !del[x]) { vstd[x] = 1; if(mx[x]==-1 || pathy(mx[x])) { my[y] = x; mx[x] = y; return 1; } } } return 0; } void MaxMatch() { int i, x, y, res = 0; memset(del, 0, sizeof(del)); memset(mx, -1, sizeof(mx)); memset(my, -1, sizeof(my)); for(x = 1; x <= nv; x++) { memset(vstd, 0, sizeof(vstd)); res += pathx(x); } printf("%d", res); for(i = 1; i <= nv; i++) { if(grp[i]==0) //如果是X[]的点 { y = mx[i]; if(y==-1) continue; mx[i] = -1; //去掉这条最大匹配边,寻找完后不用加回来,为什么? my[y] = -1; // if(del[y]) continue; 个人觉得这里应该判断一下的,可是不判断也一样过 del[i] = 1; //假设它是最小点覆盖集中一点 memset(vstd, 0, sizeof(vstd)); if(!pathy(y)) //如果没有增广路径. printf(" %d", i-1); //那么该点就是最小点覆盖集中的点. else del[i] = 0; } else { x = my[i]; if(x==-1) continue; mx[x] = -1; my[i] = -1; if(del[x]) continue; del[i] = 1; memset(vstd, 0, sizeof(vstd)); if(!pathx(x)) printf(" %d", i-1); else del[i] = 0; } } printf("\n"); } int main() { int cas, i, s, t; scanf("%d", &cas); while(cas--) { scanf("%d %d", &nv, &ne); memset(grp, 0, sizeof(grp)); memset(wet, 0, sizeof(wet)); for(i = 1; i <= nv; i++) scanf("%d", &grp[i]); for(i = 1; i <= ne; i++) { scanf("%d %d", &s, &t); s++;t++; if(grp[s]==0 && grp[t]==1) wet[s][t] = 1; if(grp[s]==1 && grp[t]==0) wet[t][s] = 1; } MaxMatch(); } return 0; }