清华OJ:PA2-3 旅行商(TSP)最简解决方案

注:本文只提供一个基本的简明的解决方案,至于如何理解拓扑排序,题目与拓扑排序之间更深层的联系等不作讨论。

题目:https://dsa.cs.tsinghua.edu.cn/oj/problem.shtml?id=1147

分析:

题目提示使用拓扑排序,那么算法一定是基于拓扑排序的框架再加一些额外的操作,于是有两个关键点,写对了,就能满分:

1.拓扑排序:

策略:将所有入度为0的顶点入栈,弹出栈顶元素,若此元素存在入度为1的邻居,将其入栈并将此邻居的入度-1,重复直到栈空。

实现:

void TSort(){
	for(int k=0;k<n;k++)if(!adjList[k].in)stack[++top]=k;
	while(top){
		int v=stack[top--];
		for(ENode *p=adjList[v].fstEdge;p;p=p->succ){	
			if(!(--adjList[p->vsub].in))stack[++top]=p->vsub;
		}
	}	
}

2.将题意与拓扑排序结合:

题目需要求的变量可等效地理解为求图的最大路径上的顶点数,注意到根据此题,顶点数=路径长度+1,于是问题转换为求图的最大路径长度,而图的最大路径长度就是到所有顶点的最大路径长度的最大值,如何求得到每个顶点的最大路径长度呢?我们知道拓扑排序算法将遍历图的每个入度为0的顶点的邻居,那么可采用动态规划的策略,为每个顶点增设一个长度属性,每遍历一个入度为0的顶点的邻居,此邻居的长度属性就更新为此邻居的长度属性与此入度为0的顶点的长度属性+1之间的较大者,更新后的值即当前到此邻居的最大路径长度,算法结束后,将得到到每个顶点的最大路径长度。为提升算法效率,可增设一记录图最大路径长度的变量,每次更新完一个顶点的长度属性后,就将此变量更新为此顶点的长度属性与此变量之间的较大者,算法结束后,将得到图的最大路径长度。

代码:

#include<cstdio>
#define MAXSIZE 1000000
#define GetMax(a,b) a>b?a:b
//注意全局变量数组的元素都会自动初始化为0 
struct ENode{
	int vsub;
	ENode *succ;
};
struct VNode{
	int in,len;//相对于邻接表结构,额外添加了属性len以计算到每个顶点的最大路径 
	ENode *fstEdge;	
};
VNode adjList[MAXSIZE];ENode *t;
int visited[MAXSIZE],stack[MAXSIZE],top=0,maxlen=0,n,e,i,j;
void TSort(){
	for(int k=0;k<n;k++)if(!adjList[k].in)stack[++top]=k;
	while(top){
		int v=stack[top--];
		for(ENode *p=adjList[v].fstEdge;p;p=p->succ){	
		//策略:动态规划-不断的更新到每个入度为0的顶点的邻居的最大路径长度
//相对于拓扑排序,额外添加了下述2句以更新到每个邻居的最大路径长度和记录图的最大路径长度 
			adjList[p->vsub].len=GetMax(adjList[v].len+1,adjList[p->vsub].len);
			maxlen=GetMax(adjList[p->vsub].len,maxlen);
			if(!(--adjList[p->vsub].in))stack[++top]=p->vsub;
		}
	}	
}
int main(){
	scanf("%d%d",&n,&e);
	for(int k=0;k<e;k++){
		scanf("%d%d",&i,&j);i--;j--;
		t=new ENode;t->vsub=j;adjList[j].in++;
		t->succ=adjList[i].fstEdge;adjList[i].fstEdge=t;
	}
	TSort();printf("%d\n",maxlen+1);//最后求的是最大路径包含的顶点数,故需要+1 
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37729102/article/details/83177125