Quantcast
Channel: AlanYume »最小路径覆盖
Viewing all articles
Browse latest Browse all 2

最小路径覆盖的注意点

$
0
0

今天做了两个最小路径覆盖的题目,总算是理解了Accept的《最小路径覆盖问题值得注意的地方》 在讲些什么了。

注意:下面博文里所说的最小路径覆盖 与图论里的概念最小路径覆盖 有所区别。

为了便于区分,如果所指的是图论里的最小路径覆盖,会在后面注明;否则默认不是。

最小路径覆盖(图论):

  • 就是在图中找最少的路径,使之覆盖了图中的所有顶点,且任何一个顶点有且只有一条路径与之关联两路径不允许存在交点

最小路径覆盖:

  • 是指在一个有向图中,找出最少的几条路径,用它们来覆盖全图(两个路径允许有交点存在

 

 

 

 

以下内容转自:博客Accept

首先,最小路径覆盖(图论)=总节点数-最大匹配数。这个应该已经是路人皆知了。

所谓最小路径覆盖,是指在一个有向图中,找出最少的几条路径,用它们来覆盖全图。

这里说的值得注意的地方,如果有向图的边有相交的情况,那么就不能简单的对原图求二分匹配了

举个例子,假设有图:1->2     2->5     2->3      4->2,事实上,这其实就是两条边:1->5  4->3 ,节点2只是他们的一个交点

如果只是简单的在原图的基础上求二分匹配,那么得到的匹配答案是2,最小路径覆盖答案便是5-2=3。

可是随便一看都能看看出端倪,这个图中,只需要两个点便可以探索完整个地图,这里最小路径覆盖数明显是2。

问题究竟出在哪里呢?其实就和这个交点2有关。既然边有相交,那么他们的连通性也应该连通下去。

解决的办法是对原图进行一次闭包传递(也就是flody),于是便增加了四条边:1->3   1->5   4->3  4->5

这时再求最大匹配数,匹配答案便是3,最小路径覆盖值为2,这是正确答案!

 

 

例题:

现在,已经弄明白了两种不同的最小路径覆盖的概念已经对应的求法,下面就给出两个例题应用下吧:

  • HDU 1151 Air Raid
    • 因为题目明确给出了“It is also known that starting from an intersection and walking through town's streets you can never reach the same intersection i.e."(即:两个路径定不存在交点),所以不需求一次传递闭包,直接用 “最小路径覆盖=总节点数-最大匹配数”即可。
    • #include <iostream>
      #include <cstdio>
      #include <cstring>
      using namespace std;
      
      const int kMaxN = 130;
      
      struct Edge{
      	int to, next_;
      };
      
      int n, m;
      int edge_size, head[kMaxN];
      Edge edge[kMaxN];
      bool used[kMaxN];
      int linker[kMaxN];
      
      void InitEdge(){
      	edge_size = 0;
      	memset(head, -1, sizeof(head));
      }
      
      void AddEdge(int from, int to){
      	edge[edge_size].to = to;
      	edge[edge_size].next_ = head[from];
      	head[from] = edge_size++;
      }
      
      void Read(){
      	scanf("%d %d", &n, &m);
      	InitEdge();
      	for(int i = 0; i < m; i++){
      		int u, v;
      		scanf("%d %d", &u, &v);
      		AddEdge(u, v);
      	}
      }
      
      int Dfs(int u){
      	for(int e_id = head[u]; ~e_id; e_id = edge[e_id].next_){
      		int v = edge[e_id].to;
      		if(used[v] == false){
      			used[v] = true;
      			if(linker[v] == -1 || Dfs(linker[v])){
      				linker[v] = u;
      				return 1;
      			}
      		}
      	}
      	return 0;
      }
      
      void Solve(){
      	int ret = 0;
      	memset(linker, -1, sizeof(linker));
      	for(int i = 1; i <= n; i++){
      		memset(used, false, sizeof(used));
      		ret += Dfs(i);
      	}
      	printf("%d\n", n - ret);
      }
      
      int main(){
      	int test;
      	scanf("%d", &test);
      	while(test--){
      		Read();
      		Solve();
      	}
      	return 0;
      }
  • POJ 2594 Treasure Exploration
    • 因为题目明确给出了“You should notice that the roads of two different robots may contain some same point.”(即,两个路径是可以相交的),所以必须先求一次闭包,才可以保证“最小路径覆盖=总节点数-最大匹配数”的正确性
    • #include <iostream>
      #include <cstdio>
      #include <cstring>
      using namespace std;
      
      const int kMaxN = 510;
      
      int n, m;
      bool G[kMaxN][kMaxN], used[kMaxN];
      int linker[kMaxN];
      
      bool Read(){
      	memset(G, false, sizeof(G));
      	scanf("%d %d", &n, &m);
      	if(n == 0 && m == 0) return false;
      	for(int i = 0; i < m; i++){
      		int u, v;
      		scanf("%d %d", &u, &v);
      		G[u][v] = true;
      	}
      	return true;
      }
      
      void Froyd(){
      	for(int i = 1; i <= n; i++){
      		for(int j = 1; j <= n; j++){
      			for(int k = 1; k <= n; k++){
      				G[i][j] |= (G[i][k] && G[k][j]);
      			}
      		}
      	}
      }
      
      int Dfs(int u){
      	for(int v = 1; v <= n; v++){
      		if(G[u][v] && used[v] == false){
      			used[v] = true;
      			if(linker[v] == -1 || Dfs(linker[v])){
      				linker[v] = u;
      				return 1;
      			}
      		}
      	}
      	return 0;
      }
      
      int MaxMatch(){
      	int ret = 0;
      	memset(linker, -1, sizeof(linker));
      	for(int i = 1; i <= n; i++){
      		memset(used, false, sizeof(used));
      		ret += Dfs(i);
      	}
      	return ret;
      }
      
      void Solve(){
      	Froyd();
      	printf("%d\n", n - MaxMatch());
      }
      
      int main(){
      	while(Read()){
      		Solve();
      	}
      	return 0;
      }

Viewing all articles
Browse latest Browse all 2

Trending Articles