Hdu-5915 The Fastest Runner Ms. Zhang(环套树DP)

Problem Description
Ms. Zhang is a journalist from Hong Kong, and she runs very very fast, so every one calls her “The fastest runner”. There are n cities (numbered from 1 to n) and n roads in the country, the roads are undirected. It costs 1 unit of time to go through each road. There exists at least one path between any pair of cities. Now Ms. Zhang can start her interview in city S, visit all of the n cities and finish her interview in city T. Since Ms. Zhang’s interview is simple and naive, the interview does not cost any time. Can you help Ms. Zhang to find the optimal S and T that minimise the total traveling time of Ms. Zhang? If there are multiple optimal solutions, output the solution with the smallest S. If there are still multiple solutions, output the solution with the smallest T.
 

Input
The first line contains only one integer T ( T40), which indicates the number of test cases.

Each test case contains n + 1 lines.

The first line contains one integer 1n105.

In the next n lines, each line contains two integers x and y indicating there is a road between city x and city y.

It is guarenteed that there does not exist a road connecting one city to itself or two roads connecting the same pair of cities.
 

Output
For each test case, output one line “Case #x: t S T ”, where x is the case number(starting from 1),t is the minimal total traveling time, S and T are the index of starting and ending city.
 

Sample Input
 
   
1 10 7 1 5 3 4 5 8 9 6 4 8 6 2 7 10 3 4 1 9 7
 

Sample Output
 
   
Case #1: 10 1 10


题意:给定一个环套树的图,让找一个起点和终点,使得从起点开始每个点访问一次到终点的最小路程最少,问最小路程是多少。



分析:找到环后分两种情况,起点终点在一棵子树中,那么答案为2*n-circle-dis(s,t),或者起点终点在不同子树中,那么答案为2*n-dis(U,V)-2-dis(U,u)-dis(V,v),前者树形DP时就能统计出,后者需要对环单独扫两遍求解。


#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define INF 0x3f3f3f3f
#define eps 1e-9
#define MOD 1000000007
#define N 100005
using namespace std;
int T,n,time,u,v,jud[N],vis[N],Mans[N][2],cho[N][2],MAXVAL;
vector G[N],a;
stack  S;
struct point
{
	int u,v;
	point() {}
	point(int x,int y)
	{
		if(x > y) swap(x,y);
		u = x;
		v = y;
	}
	friend bool operator < (point a,point b)
	{
		if(a.u == b.u) return a.v < b.v;
		return a.u < b.u; 
	} 
	void write()
	{
		printf("Case #%d: %d %d %d\n",++time,MAXVAL,u,v);
	}
}Point;
void Up_date(int u,int v)
{
	if((Mans[v][1] + 1 > Mans[u][0]) || (((Mans[v][1] + 1) == Mans[u][0]) && (cho[v][1] < cho[u][0])))
	{
		Mans[u][0] = Mans[v][1] + 1;
		cho[u][0] = cho[v][1]; 
	}
	if(Mans[u][0] > Mans[u][1] || ((Mans[u][0] == Mans[u][1]) && (cho[u][0] < cho[u][1])))
	{
		swap(Mans[u][0],Mans[u][1]);
		swap(cho[u][0],cho[u][1]);
	}
}
void dfs(int u,int fa)
{
	cho[u][0] = cho[u][1] = u;
	for(int v : G[u])
	 if(v != fa && !jud[v])
	 {
	 	dfs(v,u);
	 	Up_date(u,v);	
	 } 
	if((2*n - a.size() - (Mans[u][0] + Mans[u][1]) < MAXVAL) || ((2*n - a.size() - (Mans[u][0] + Mans[u][1]) == MAXVAL) && point(cho[u][1],cho[u][0]) < Point))
	{
		MAXVAL = 2*n - a.size() - (Mans[u][0] + Mans[u][1]);
		Point =  point(cho[u][1],cho[u][0]); 
	}
}
bool Circle(int u,int fa)
{
	S.push(u); 
	vis[u] = true;
	for(int v : G[u]) 
	 if(v != fa)
	  if(!vis[v]) 
	  {
	  	 if(Circle(v,u)) return true;
	  }
	  else 
	  {
	  	 while(S.top() != v)
	  	 {
	  	 	a.push_back(S.top());
	  	 	S.pop();
		 }
		 a.push_back(S.top());
		 S.pop();
		 return true;
	  } 
	S.pop();
	return false;
}
void deal_circle(int op)
{
	int temp_val = (-2)*N,num = 0,temp_num = 0;
	for(int u : a)
	{
		if(num++)
		{
			int got_val = 2*n - 2 - (Mans[u][1] + -1*num*op + temp_val + a.size()*(op == 1 ? 1 : 0));
			if(got_val < MAXVAL || ((got_val == MAXVAL) && point(temp_num,cho[u][1]) < Point))
			{
				MAXVAL = got_val;
				Point = point(temp_num,cho[u][1]);
			}
		}
		if(temp_val < Mans[u][1] + num*op || (temp_val == Mans[u][1] + num*op && temp_num > cho[u][1]))
		{
			temp_val = Mans[u][1] + num*op;
			temp_num = cho[u][1];
		} 
	}
}
int main()
{
	scanf("%d",&T);
	while(T--)
	{
		a.clear();
		memset(jud,0,sizeof(jud));
		memset(vis,0,sizeof(vis));
		memset(Mans,0,sizeof(Mans));
		MAXVAL = N*2;
		scanf("%d",&n);
		for(int i = 1;i <= n;i++) G[i].clear();
		for(int i = 1;i <= n;i++)
		{
			scanf("%d %d",&u,&v);
			G[u].push_back(v);
			G[v].push_back(u);
		}
		while(!S.empty()) S.pop();
 		Circle(1,-1);
		for(int u : a) jud[u] = true;
		for(int u : a) dfs(u,-1);
		deal_circle(-1);
		deal_circle(1);
		Point.write(); 
	}
}



你可能感兴趣的:(ACM,DP动态规划,好题,不会做,图论,贪心)