树的最大连通分支问题

问题描述

给定一棵树 T,树中每个顶点 u 都有一个权 w(u),权可以是负数。现在要找到树 T 的一个连通子图使该子图的权之和最大

对于给定的树 T,编程计算树 T 的最大连通分支

数据输入

一行有1个正整数n,表示树Tn个顶点,顶点的编号为1~n

第二行有n个整数,表示顶点的权值

接下来n-1行,每行有两个整数uv,表示顶点uv相连

结果输出

个整数,表示最大连通分支的权值

输入输出样例

Input                           Output

6                               4
-1 1 3 1 -3 2
4 1
1 3
1 2
4 5
6 5

算法分析()

顶层问题:如何确定哪些顶点存在于最大连通子图中?

分解问题:如何求有顶点4存在的最大连通分支?

再次分解:考虑顶点4两棵子树

算法分析() 

最大连通分支在子树或树中,因此对树进行遍历,依次求出以每个结点为树根的最大连通分支权值

两个性质:最优子结构性质、子问题重叠性质

动态规划!!

     

算法步骤

对于叶子结点:最大连通分支的权值为该点的权值

某一结点的最大连通权值>0,则将其值加到它的父亲结点的最大连通权值,反之舍弃该值

最终求出根结点的最大连通权值,结束遍历

所求最大连通分支的权值,即为结点中最大连通权值的最大值

 C++代码实现

#include <iostream>
#include <vector>
#include <list>
#include <queue>
#include <chrono>
#include <fstream>
#include <algorithm>
using namespace std;
using namespace chrono;

//邻接链表:储存无向图
vector<list<int> > adjList;

//每个结点 
struct Node {
	int parent; //父结点
	int wMax;   //以每个结点为树根的最大连通分支权值 
	int level;  //层次 
	bool visit; //是否被访问过 
};

Node* node = NULL;
vector<int> List;

//广度优先搜索:用于确定所有结点的level和parent
void bfs()
{
	queue<int> que;      //队列 
	que.push(1);         //以结点1为树根 
	node[1].parent = 0;
	node[1].visit = 1;
	
	while(!que.empty())
	{
		int cur = que.front();
		List.push_back(cur);
		que.pop();
		for(list<int>::iterator it = adjList[cur].begin(); it != adjList[cur].end(); ++it)
		{
			if(!node[*it].visit)
			{
				node[*it].parent = cur;
				node[*it].level = node[cur].level + 1; //后代的层次 = parent层次 + 1 
				que.push(*it);
				node[*it].visit = 1;
			}
		}
	}
}

//自定义比较函数:按level降序排列 
bool cmp(const Node& a, const Node& b) {
	return a.level > b.level;
}

int main()
{
	auto start = system_clock::now();
	ifstream src("20.txt");
	
	int n;
	src >> n;
	
	adjList.assign(n+1, list<int>()); //邻接表:n+1个list<int>构成的vector 
	node = new Node[n+1]; //n+1个 
	
	//初始化所有wMax为结点的权值 
	for(int i = 1; i <= n; ++i)
	{
		src >> node[i].wMax;
		node[i].level = 0;
		node[i].visit = 0;
	}
	
	//将(u, v)和(v, u)加入adjList 
	int u, v;
	for(int i = 1; i < n; ++i)
	{
		src >> u >> v;
		adjList[u].push_back(v);
		adjList[v].push_back(u);
	}
	src.close();
	
	bfs(); //广度优先搜索:用于确定所有结点的level和parent
	
	//自底向上:依次求出以每个结点为树根的最大连通分支权值 
	for(int i = 0; i < n; ++i)
	{
		int parent = node[List[n-1-i]].parent;
		if(node[i].wMax > 0)
			node[parent].wMax += node[i].wMax;
	}
	
	//遍历所有结点的wMax,取最大值作为最终结果输出 
	int maxValue = -INT_MAX;
	for(int i = 1; i <= n; ++i)
		maxValue = max(maxValue, node[i].wMax);
	
	ofstream out("result.txt");
	out << maxValue;
	out.close();
	
	auto end = system_clock::now();
	auto duration = duration_cast<microseconds>(end - start);
	cout <<  "Problem size: " << n << "\nRunning time: " << double(duration.count()) * microseconds::period::num / microseconds::period::den << "s";
	return 0;
}
发布了91 篇原创文章 · 获赞 142 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/leelitian3/article/details/89390612
今日推荐