快顶不住了,理解了多少,先写出来再说;
题意:
军队里面要展开实战演练,已经将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;
}