刚开始看到这个题目的时候就觉得想法很明了,就是不知道如何去匹配...
去网上看了不少人的解题报告,但是对于刚接触“最小边覆盖”的我来说....还是很困难滴....于是自己又开始一如以往学习“最大独立集”、“最小点覆盖的”的思考方式啦:在了解一个看似高深的知识点之前,粗略了解这是个什么东东,那么看概念也会更好理解,(希望此博客在自己以后回头来看会一目明了,也对刚接触“最小边覆盖”的人有帮助(万分感到荣幸)):
首先把题目的第一个案例图形化(第一,图形好理解,第二,很多人看到文字就烦啦。第三,图论不画图怎么可以捏),我们把交叉路看成点,街道看成边,就如下图:
要求选择最少的伞兵降落在某些交叉口,使他们走完所有的交叉口,(注意是单向边)从图中很容易选择,我们在二号交叉口降落一个走到3再走到4,然后在1好交叉口降落一个,总共两个就可以访问所有的交叉口,我们就可以这样看:把3号街道和1号街道看做一条边,把2.3.4号交叉点都覆盖啦:如图
接下来是解决这个问题,用匈牙利匹配:因为刚开始接触二分匹配,我就想用街道(简化为点)去和交叉口匹配:(谁知道...如图)
接着就看看最小边覆盖和二分匹配的关系吧:(如果觉得看文字概念还是很烦..可以看下面的图形说明,不过结合文字和图形更有助理解)(摘自百度百科)
// 0MS 244K #include<stdio.h> #include<string.h> #define MAX 121 int no_in,no_st;//交叉路的数量,街道数量 bool map[MAX][MAX];//map[i][j]表示i号交叉口有一条街道可以达到j号交叉口 int link[MAX]; bool useif[MAX]; bool dfs(int t) { for(int i=1;i<=no_in;i++) { if(!useif[i] && map[t][i]) { useif[i]=true; if(link[i]==-1 || dfs(link[i])) { link[i]=t;return true; } } } return false; } int match() { int sum=0; memset(link,-1,sizeof(link)); for(int i=1;i<=no_in;i++) { memset(useif,false,sizeof(useif)); if(dfs(i)) sum++; } return sum; } int main() { int T; int a,b; scanf("%d",&T); while(T--) { memset(map,0,sizeof(map)); scanf("%d%d",&no_in,&no_st); for(int i=1;i<=no_st;i++) { scanf("%d%d",&a,&b); map[a][b]=1;//注意是单项路 } printf("%d\n",no_in-match()); } return 0; }