Тестовый кубок "Голубого моста" Вопрос J: Поездка министра

很久以前,T王国空前繁荣。为了更好地管理国家,王国修建了大量的快速路,用于连接首都和王国内的各大城市。 

   为节省经费,T国的大臣们经过思考,制定了一套优秀的修建方案,使得任何一个大城市都能从首都直接或者通过其他大城市间接到达。同时,如果不重复经过大城市,从首都到达每个大城市的方案都是唯一的。 

   J是T国重要大臣,他巡查于各大城市之间,体察民情。所以,从一个城市马不停蹄地到另一个城市成了J最常做的事情。他有一个钱袋,用于存放往来城市间的路费。 

   聪明的J发现,如果不在某个城市停下来修整,在连续行进过程中,他所花的路费与他已走过的距离有关,在走第xx千米到第x+1x+1千米这一千米中(xx是整数),他花费的路费是x+10x+10这么多。也就是说走11千米花费1111,走22千米要花费2323。 

   J大臣想知道:他从某一个城市出发,中间不休息,到达另一个城市,所有可能花费的路费中最多是多少呢?

Проблема в течение длительного времени , чтобы написать эту слабую курицу, которая является первым контактом к диаметру концепции дерева
деревьев диаметра является деревом дальше расстояние между любыми двумя точками ( которые также называют самой длинной цепью)
двух диаметров дерева Метод решения (1) Дерево dp (2) Дважды dfs (bfs)
Здесь нам нужно знать два свойства дерева
(1) Начиная с любой точки, суммой самой длинной цепи и второй самой длинной цепи в этой точке является это дерево диаметр
конкретной ссылки
здесь
(2) , начиная с любой точки, через поиск , чтобы найти наиболее удаленную точку, то эта точка, безусловно , одна конечной точки диаметра дерева
точки , почему нужно сначала найти конечную точку
с этими 2 Вы можете ответить на этот вопрос с точки зрения знаний.
Прежде всего, я представлю код bfs (dfs легко вставляет стек в JAVA, поэтому, если вы используете JAVA, лучше всего использовать BFS)

package lan4A_C;
import java.io.*;
import java.util.*;
public class TestJ {
	static int MAX = 10010;
	static int n;
	static int p[]; //存每个点的一条边的编号
	static int u[]; //边的起点
	static int v[]; //边的终点
	static int w[]; //边的权值
	static int next[]; // 下一条边编号
	static int dist[]; // 到每一个的距离
	static boolean vis[]; // 点是否访问过
	static int get(int x){ // 路径转费用
		int t = 10;
		int sum = 0;
		for(int i = 1;i <= x;i++){
			sum += i+t;
		}
		return sum;
	}
	static int id = 1;
	static void add(int a,int b,int x){
		u[id] = a;
		v[id] = b;
		w[id] = x;
		next[id] = p[a];
		p[a] = id++;
	}
	static void bfs(int k){
		Queue<Integer> q = new LinkedList<Integer>();
		q.add(k);
		Arrays.fill(vis, false);
		vis[k] = true;
		dist[k] = 0;
		while(!q.isEmpty()){
			int t = q.poll();
			for(int i = p[t];i != -1;i = next[i]){ // 找到这个点的第一条边编号
				if(vis[v[i]])
					continue;
				dist[v[i]] = dist[t]+w[i]; // k点到v[i]点的距离
				q.add(v[i]);
				vis[v[i]] = true; // 这个终点已经算过了
			}
		}
	}
	public static void main(String[] args) throws IOException{
		StreamTokenizer re = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
		PrintWriter pr = new PrintWriter(new OutputStreamWriter(System.out));
		re.nextToken(); n = (int)re.nval;
		p = new int[MAX]; u = new int[MAX*2]; v = new int[MAX*2]; w = new int[MAX*2]; next = new int[MAX*2];
		vis = new boolean[MAX]; dist = new int[MAX];
		Arrays.fill(p,-1);
		Arrays.fill(next,-1);
		for(int i = 1;i < n;i++){
			re.nextToken();int a = (int)re.nval;
			re.nextToken();int b = (int)re.nval;
			re.nextToken();int x = (int)re.nval;
			add(a,b,x);
			add(b,a,x);
		}
		bfs(1);
		int k = 1;
		for(int i = 2;i <= n;i++)
			if(dist[i] > dist[k])
				k = i;  // 最远距离 第一个端点
//		System.out.println(k);
		bfs(k);
		int t = dist[1];
		for(int i = 1;i <= n;i++)
			if(dist[i] > t)
				t = dist[i];
//		System.out.println(t);
		long ans = get(t);
		pr.println(ans);
		pr.flush();
	}
}

Ниже приведен код ДП

package lan4A_C;
import java.io.*;
import java.util.Arrays;
public class TestJDP {
	static int MAX = 10010;
	static int n;
	static int p[]; //存每个点的一条边的编号
	static int u[]; //边的起点
	static int v[]; //边的终点
	static int w[]; //边的权值
	static int next[]; // 下一条边编号
	static int d[] = new int[MAX];
	static boolean vis[] = new boolean[MAX];
	static int ans = 0;
	static int id = 0;
	static void add(int a,int b,int x){
		u[id] = a;
		v[id] = b;
		w[id] = x;
		next[id] = p[a];
		p[a] = id++;
	}
	static int get(int x){
		int t = 10;
		int sum = 0;
		for(int i = 1;i <= x;i++){
			sum += i+t;
		}
		return sum;
	}
	static void dp(int x){
		vis[x] = true;
		for(int i = p[x];i != -1;i = next[i]){
			int y = v[i];
			if(vis[y])
				continue;
			dp(y); // 先计算儿子结点的最长链
			// ans每次都为最长链加次长链的结果
			// d[x]表示从x结点出发的最长链,而如果我们之前找到的一个方向的
			//最长链,现在发现这个点从另外一个儿子结点出去,那边还有更长的最
			//长链,我们就把另外那条链当做最长链  d[x]+d[y]+w[w] 表示的是当
			//前已知的最长链加上从另外一个儿子结点出发的最长链,取最大值,这
			//个值则必然是最大值
			ans = Math.max(ans, d[x]+d[y]+w[i]);
			d[x] = Math.max(d[x], d[y]+w[i]); // d[x]每次都为最长链
		}
	}
	public static void main(String[] args) throws IOException{
		StreamTokenizer re = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
		PrintWriter pr = new PrintWriter(new OutputStreamWriter(System.out));
		re.nextToken(); n = (int)re.nval;
		p = new int[MAX]; u = new int[MAX*2]; v = new int[MAX*2]; w = new int[MAX*2]; next = new int[MAX*2];
		Arrays.fill(p, -1);
		Arrays.fill(next, -1);
		Arrays.fill(vis, false);
		for(int i = 1;i < n;i++){
			re.nextToken();int a = (int)re.nval;
			re.nextToken();int b = (int)re.nval;
			re.nextToken();int x = (int)re.nval;
			add(a,b,x);
			add(b,a,x);
		}
		dp(1);
		pr.println(get(ans));
		pr.flush();
	}
}

Вы можете видеть, что кто-то здесь немного неосведомлен. Если список смежности реализован с помощью массива? ? ? Я не понимал странности наблюдения. Поскольку эта слабая курица имеет место
, позвольте мне познакомить вас с реализацией
массива списка смежности. Примечание: номер ребра списка смежности очень важен
(1) Мы используем u, v, w 3 массива для хранения 3 информации о ребре ( Начальная точка, конечная точка, вес)
(2) Мы используем массив p для хранения номера первого ребра каждой вершины, а следующий массив для хранения, если некоторые вершины имеют более одного ребра, следующий массив будет играть роль
Давайте опишем это подробно ниже.
Например, у нас есть 5 точек
1 2 3 4 5
У нас есть 4 пронумерованных ребра
1 2 3 4
1: 2-3 8
2: 3-4 5
3: 2-1 3 В настоящее

время только 3 ребра это лень писать не хочется
считаны в первых сторон:
[. 1] U V 2 = [1.] W = 3 [1] . 8 = Р [2] = 1... мы должны быть ясно , внутри сторона информации индекса массива Это номер ребра, поэтому мы должны четко различать эту вещь. Каждый раз, когда мы ищем ее, мы ищем ее по номеру ребра. Массив p определяет, какое ребро соответствует этой точке. При
чтении второго ребра:
u [2] = 3 v [2] = 4 w [2] = 5 p [3] = 2 При
чтении третьего ребра:
u [3] = 2 v [3] = 1 w [3] = 3 p [2] = 3 (Обратите внимание, что если мы читаем так Если мы введем, мы потеряем информацию о первом ребре второй точки, поэтому здесь мы вводим следующий массив)
Таким образом , мы читаем в
U [3] = 2, v
[3] = 1, ш [3] = 3, следующая [3] = р [2] (следующая [3] = 1), р [2] = 3 мы до этого момента соответствует ребру , присутствующие на следующем массиве ,
когда мы находим мы найдем этот
р [2]: найдено первая стороны и следующий [р [2]] вторая сторона будет найти его
, если Слабая курица до сих пор не объяснена четко, вы можете обратиться по ссылке ниже
здесь

Опубликовано 32 оригинальных статей · Хвала 5 · Посещений 862

рекомендация

отblog.csdn.net/shizhuba/article/details/104917250