D. Maximize the Root个人题解

Problem - 1997D - Codeforces

这题是一个树,我用拓扑排序替代dfs去遍历树

拓扑便利原理:从叶节点开始,因为入度为0,然后删除叶,那么叶的父节点就成为叶,不断迭代

放代码,解释在代码里

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1000005;
long long dis[MAXN],val[MAXN]; 
int in[MAXN];     
queue<int> q;

struct node {
	int v, next; 
} edge[MAXN];

int num;  
int head[MAXN];

void add(int i, int p) {
	edge[++num].next = head[i];
	head[i] = num;
	edge[num].v =p;
}
void tupo() {
	while (!q.empty()) {
		int t = q.front();//叶节点
		q.pop();
		if (t == 1) continue; // skip根节点
		for (int i = head[t];i!=0; i = edge[i].next) {//遍历与节点t直接相连的所有其他节点
			int v = edge[i].v;//v是树节点的标号1,2,3,4,……从叶到根
			if (dis[t] >= val[v]) {
				dis[v] = min(dis[v], (v == 1) ? dis[t] : (dis[t] + val[v]) / 2);
			} else {//t存入了树枝的最小值哦
				dis[v] = min(dis[v], (v == 1) ? dis[t] : min(dis[t], val[v]));
			}
			in[v]--; 
			if (in[v] == 0) q.push(v); 
		}
	}
}

int main() {
	int t;
	cin >> t;
	while (t--) {
		while (!q.empty()) q.pop();
		
		int n;
		cin >> n;
		
		for (int i = 1; i <= n; i++) {
			cin >> val[i];
			head[i] = 0;
		}
		memset(in, 0, sizeof in);
		fill(dis + 1, dis + n + 1, LLONG_MAX);//dis是从每个节点到根节点的最小代价
		
		for (int i = 2; i <= n; i++) {
			int p;
			cin >> p;
			add(i, p); // i的父节点为p
			in[p]++;
		}
		for (int i = 2; i <= n; i++) {
			if (in[i] == 0) {
				q.push(i);
				dis[i] = val[i]; // 叶节点
			}
		}
		num = 0;
		tupo();
		cout << dis[1] + val[1] << endl; 
	}
	return 0;
}

还有dfs版本,不过time error,我是做不了了

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxx = 20006;
vector<ll> tr[maxx];
ll val[maxx], copval[maxx], minn;
void dfs(int x) {
	minn = INT_MAX;
	for (int i = 0; i < tr[x].size(); i++) {
		int child = tr[x][i]; 
		dfs(child);
	//	cout<<"minn1="<<minn<<" "<<endl;
		minn = min(minn, copval[child]);
	//	cout<<"copval[child]="<<copval[child]<<" "<<endl;
	//	cout<<"minn2="<<minn<<" "<<endl;
	}
	if (minn == INT_MAX) {
		copval[x] = val[x];
	} else if (x == 1) {
		val[1] += minn;
	} else {
		copval[x] = (val[x] < minn) ? (val[x] + minn) / 2 : minn;
	}
}
void solve() {
	int n;
	cin >> n;

	for (int i = 1; i <= n; i++) {
		cin >> val[i];

	}
	for (int i = 2; i <= n; i++) {
		int parent;
		cin >> parent;
		tr[parent].push_back(i);//
	}
	dfs(1);
	cout << val[1] << endl;
}
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	ll t;
	cin >> t;
	while (t--) {
		solve();
	}
	return 0;
}
 

调不出来,你们看看怎么dfs

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值