洛谷 P2458 [SDOI2006] 保安站岗 - 树形DP

P2458 保安站岗

题意:
一棵树,每个节点部署保安都需要确定的费用,一个节点的保安负责当前节点以及与其相邻的节点,问最小的部署保安费用使得所有节点都有保安负责?

思路:
树形DP
三个状态:

  • dp[i][0]:节点 i 位置放保安的最小花费
  • dp[i][1]:节点 i 位置不放保安,但被子节点的保安看守
  • dp[i][2]:节点 i 位置不放保安,但被父节点的保安看守

状态转移:

  • dp[i][0]:节点 i 位置放保安,那么它可以合并子节点任何状态的最小值;
  • dp[i][1]:节点 i 位置不放保安,但被子节点的保安看守,那么它可以合并一个子节点的状态 0 和其余子节点的状态 1 和状态 0 的小值;
  • dp[i][2]:节点 i 位置不放保安,但被父节点的保安看守,那么它可以合并子节点除了状态 2 以外的状态。

最终答案:
min(dp[1][0],dp[1][1])

下为代码:

//>>>Qiansui
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define mem(x,y) memset(x,y,sizeof(x))
#define debug(x) cout << #x << " = " << x << endl
#define debug2(x,y) cout << #x << " = " << x << " " << #y << " = "<< y << endl
//#define int long long

using namespace std;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<ull,ull> pull;
typedef pair<double,double> pdd;
/*

*/
const int maxm=15e2+5,inf=0x3f3f3f3f,mod=998244353;
int n, k[maxm], m;
vector<int> e[maxm];
vector<vector<int>> dp(maxm, vector<int>(3,0));

void dfs(int u,int fa){
	dp[u][0] = k[u];
	dp[u][2] = dp[u][1] = 0;
	int pos = inf,sum = 0;
	for(auto v : e[u]){
		if(v == fa) continue;
		dfs(v,u);
		dp[u][0] += min(dp[v][0], min(dp[v][1], dp[v][2]));
		dp[u][2] += min(dp[v][0], dp[v][1]);
		dp[u][1] += min(dp[v][0], dp[v][1]);
		if(dp[v][0] < dp[v][1]) ++sum;
		else pos = min(pos, dp[v][0] - dp[v][1]);
	}
	if(!sum) dp[u][1] += pos;
	return ;
}

void solve(){
	cin>>n;
	int root;
	for(int i=0; i < n; ++i){
		int id, r;
		cin >> id;
		cin >> k[id] >> m;
		while(m--){
			cin >> r;
			e[id].push_back(r);
			e[r].push_back(id);
		}
	}
	dfs(1, 0);
	cout << min(dp[1][0], dp[1][1]) << '\n';
	return ;
}

signed main(){
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	int _=1;
	// cin>>_;
	while(_--){
		solve();
	}
	return 0;
}

仅存单向边做法不推荐

//>>>Qiansui
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define mem(x,y) memset(x,y,sizeof(x))
#define debug(x) cout << #x << " = " << x << endl
#define debug2(x,y) cout << #x << " = " << x << " " << #y << " = "<< y << endl
//#define int long long

using namespace std;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<ull,ull> pull;
typedef pair<double,double> pdd;
/*

*/
const int maxm=15e2+5,inf=0x3f3f3f3f,mod=998244353;
int n, k[maxm], m;
vector<int> e[maxm];
vector<vector<int>> dp(maxm, vector<int>(3,0));

void dfs(int u){
	dp[u][0] = k[u];
	dp[u][2] = dp[u][1] = 0;
	int pos = inf;
	for(auto v : e[u]){
		dfs(v);
		dp[u][0] += min(dp[v][0], min(dp[v][1], dp[v][2]));
		dp[u][2] += min(dp[v][0], dp[v][1]);
		dp[u][1] += min(dp[v][0], dp[v][1]);
		pos = min(pos, dp[v][0] - min(dp[v][0], dp[v][1]));
	}
	dp[u][1] += pos;
	return ;
}

void solve(){
	cin>>n;
	int root;
	vector<bool> vis(n+1, false);
	for(int i=0; i < n; ++i){
		int id, r;
		cin >> id;
		cin >> k[id] >> m;
		while(m--){
			cin >> r;
			e[id].push_back(r);
			vis[r]=true;
		}
	}
	for(int i = 1; i <= n; ++i){
		if(!vis[i]){
			root=i; break;
		}
	}
	dfs(root);
	cout << min(dp[root][0], dp[root][1]) << '\n';
	return ;
}

signed main(){
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	int _=1;
	// cin>>_;
	while(_--){
		solve();
	}
	return 0;
}

相关资料

思路来源:
https://www.luogu.com.cn/blog/Parabola/solution-p2458

posted on 2023-07-18 23:31  Qiansui  阅读(36)  评论(0编辑  收藏  举报