[HDU] 2196 Computer 有点树形dp的味道

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=2196

方法:

设FSdist[i].dist1为第i个节点到叶子最长路径,FSdist[i].dist1.dist为路径的距离,FSdist[i].dist1.entry为路径入口,FSdist[i].dist2为次长路径(如果存在次长路径的话,dist2中的信息和dist1一样。F[i].dist1.dist是第i个节点在树种一个节点的最长路径的距离,p[i]是第i个点的直接父节点,dist(x,y)为x 到y的距离,那么

  

      {

        FSdist[i].dist1 ,   i是根节点

F[i].dist1.dist =  Max(FSdist[p[i]].dist1.dist + dist(i,p[i]),FSdist[i].dist1.dist) , FSdist[p[i]].entry !=i && i是非根节点

       Max(FSdist[p[i]].dist2.dist + dist(i,p[i]),FSdist[i].dist1) , FSdist[p[i]].entry==i && FSdist[p[i]].dist2!=NULL && i是非根节点

      Max( dist(i,p[i]),FSdist[i].dist1.dist),FSdist[p[i]].entry==i && FSdist[p[i]].dist2!=NULL && i是非根节点

      }  

      

 其实简单的来说就是,把每一个节点到叶子的最长的路径和通过父节点出去(不回来)能走的路径做比较等到最长路径的距离。找的方式就是找父节点在叶子节点的最长路径。

这里强调从父节点走出去不回来就是指通过父节点出去找到的到达叶子节点的最大路径不能是当前节点所在的那个路径,如果一个从一个父节点出去找到的最长路径不会通过该当前节点,则这就是父节点的出去找到的最长路径,可以和当前叶子叶子节点到叶子的最长路径比较。如果从一个父节点出去找到的最长路径通过该当前节点,则找次长路径,并和和当前叶子叶子节点到叶子的最长路径比较。

首先 一个深搜,获得每一个节点的FSdist[i].dist1 和FSdist[i].dist2,然后在一个深搜来实现上述逻辑,实现过程中不仅要计算每一个节点的F[i].dist1,还要去更新F[i].dist2,因为在考虑一个节点从父节点出去能走多远的时候,其实就是看父节点到叶子节点的最大路径,如果最大路径和当前节点重合就要考虑次长路径,次长路径要是没有就直接考虑当前节点到父节点的距离,无论怎么样,当和当前节点已经获得的FSdist[i].dist1,FSdist[i].dist2比较的时候,计算F[i].dist1和F[i].dist2.

代码:

#include <iostream>
#include <queue>
#include<algorithm>
using namespace std;
int n;
struct Adge
{
	int vetex;
	Adge* nextAdge;
	int dist;

};
struct Entry
{
	int id;
	int longestDist;
};
struct cmp
{
	bool operator()(Entry x,Entry y)
	{
		if(x.longestDist<y.longestDist)
			return true;
		return false;
	}
};
struct Node
{
	Adge* firstAdge;
	int id;
	int pre;
	Entry firstLong;
	Entry secondLong;
	int EntryCount ;
	int distFromRoot;
};
Node nodes[10001];
bool v[10001];
void createAdge(int st,int ed,int cost)
{
	Adge* adge = (Adge*)malloc(sizeof(Adge));////////////////
	adge->dist=cost;
	adge->vetex=ed;
	adge->nextAdge= nodes[st].firstAdge==NULL ? NULL : nodes[st].firstAdge;
	nodes[st].firstAdge=adge;
	adge = (Adge*)malloc(sizeof(Adge));/////////////////
	adge->vetex =st;
	adge->dist=cost;
	adge->nextAdge= nodes[ed].firstAdge==NULL ? NULL : nodes[ed].firstAdge;
	nodes[ed].firstAdge=adge;
}
int dfsGetLongestDistInDescendants(int root=1)
{ 
	v[root]=true;
	Adge* arc = nodes[root].firstAdge;
	priority_queue<Entry,vector<Entry>,cmp> q;
	while(arc!=NULL )
	{
		if(!v[arc->vetex])
		{
			nodes[arc->vetex].distFromRoot = nodes[root].distFromRoot+arc->dist;
			nodes[arc->vetex].pre=root;
			int dist = dfsGetLongestDistInDescendants(arc->vetex);
			Entry entry;
			entry.id = arc->vetex;
			entry.longestDist=dist+arc->dist;
			q.push(entry);
		}
		arc=arc->nextAdge;
	}
	if(q.empty())
	{
		Entry e;
		e.id=root;
		e.longestDist=0;
		q.push(e);
	}
	if(!q.empty())
	{
		nodes[root].firstLong = q.top();
		q.pop();
		nodes[root].EntryCount++;
	}
	if(!q.empty())
	{
		nodes[root].secondLong = q.top();
		q.pop();
		nodes[root].EntryCount++;
	}
	return nodes[root].firstLong.longestDist;
}
void dfsGetLongestDistInAllTree(int root=1)
{
	v[root]=true;
	Adge* arc = nodes[root].firstAdge;
	if(nodes[root].pre!=-1)
	{
		int pre =nodes[root].pre;
		int maybeLonger=-1;//maybeLonger是从父节点出发去找到一个有可能比现在找到的在叶子节点最长或次长 更长的路径的长度
		if(nodes[pre].firstLong.id!=root)
			maybeLonger=nodes[pre].firstLong.longestDist+nodes[root].distFromRoot - nodes[pre].distFromRoot;
		else if(nodes[pre].EntryCount==2)//找到的可能最长路径是原来父节点到叶子节点的次长路径,已经最长路径就是通过当前节点的 
			maybeLonger=nodes[pre].secondLong.longestDist+nodes[root].distFromRoot - nodes[pre].distFromRoot;
		else if(nodes[pre].EntryCount==1)//原来父节点到叶子节点的没有次长路径,而最长路径就是通过当前节点的,所以可能最长路径就是该节点到父节点的距离。
			maybeLonger = nodes[root].distFromRoot - nodes[pre].distFromRoot;
		if(maybeLonger>nodes[root].firstLong.longestDist)
		{
			nodes[root].secondLong = nodes[root].firstLong;
			nodes[root].firstLong.longestDist = maybeLonger;
			nodes[root].firstLong.id = pre;
			if(nodes[root].EntryCount==1)//如果该节点原来没有次长路径,现在有了
				nodes[root].EntryCount=2;
		}
		else if((nodes[root].EntryCount==2&& maybeLonger>nodes[root].secondLong.longestDist) || nodes[root].EntryCount==1)
		{
			nodes[root].secondLong.longestDist = maybeLonger;
			nodes[root].secondLong.id = pre;
			if(nodes[root].EntryCount==1)//如果该节点原来没有次长路径,现在有了
				nodes[root].EntryCount=2;
		}
	
	}

	while(arc!=NULL )
	{
		if(!v[arc->vetex])
		{
			 dfsGetLongestDistInAllTree(arc->vetex);
		}
		arc=arc->nextAdge;
	}
}
int main()
{
    while(scanf("%d",&n)!=EOF)
    {
		int ed,cost;
		for(int i=1;i<=n;i++)
		{
			nodes[i].EntryCount=0;
			nodes[i].firstAdge=NULL;
			nodes[i].pre=-1;
			nodes[i].distFromRoot=0;
		}
		for(int i=1;i<=n-1;i++)
		{
			scanf("%d %d",&ed,&cost);
			createAdge(i+1,ed,cost);
		}
		memset(v,false,sizeof(v));
		v[1] = true;
		dfsGetLongestDistInDescendants();
		memset(v,false,sizeof(v));
		v[1] = true;
		nodes[1].pre=-1;
		dfsGetLongestDistInAllTree();
		for(int i=1;i<=n;i++)
			cout<<nodes[i].firstLong.longestDist<<endl;
    }
	return 0;
}

 感谢:烦!!

       

原文地址:https://www.cnblogs.com/kbyd/p/3240925.html