UVA 10859 Placing Lampposts 树型DP -

本文详细解析了UVA-10859问题的DP算法实现思路,通过定义状态d[i][j]来表示以i为根节点时的最优解,并考虑父节点是否放置灯作为决策依据,从而有效地解决了问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目地址:http://vjudge.net/problem/UVA-10859

很明显是DP;但关键是怎么DP

题目优化的方向是a放置的灯数尽量少,被两盏灯照亮的边数b尽可能大,也就是c被一盏灯照亮的路尽可能小,a-b=c,所以c越小,b越大

综上就是,x=a+c越小越好

而且题目要求a为首要条件,b为次要条件,于是增加a的比重 x=M*a+c,便成为x=M*a+c越小越好,注意M不是越大越好,防止算数超出


既然书树形,一般都要无根树转有根树,求出fa数组保存父节点,于是状态定义为d[i] 为i为根最小的x值(包括i到其父节点的这条边)

对于一个点放不放灯,需要看上一个节点也就是父节点,所以状态定义为d[i][j],j=1表示i父节点节点放灯,0表示无

注意不能用j代表i节点是否放灯,这样就会有后效性,将放不放灯的决策留到下一个状态,这样不好判断,比如i没放灯,那么i的子结点k至少其中一个要放灯,无法确定是哪个k放灯,只会让状态转移十分混乱,所以不如定义j为i父节点是否放灯了,这样i的子结点k的状态十分明了,只需要看i放灯没

状态转移:d[i][j]=∑{d[k,j']}  k为i的子结点 具体看代码

#include <bits/stdc++.h>
using namespace std;
#define REP(i,a,b) for(int i=a;i<=(int)(b);++i)
#define REPD(i,a,b) for(int i=a;i>=(int)(b);--i)
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
const int maxn=1000+5,M=2000;
std::vector<vector<int> > Adj(maxn);
int d[maxn][2];  //x=M*a+c
bool vis[maxn][2];
int DP(int i,int j,int fa){
	int& ans=d[i][j];
	if(vis[i][j]) return ans;
	vis[i][j]=true;

	ans=j==1?M:(M+(fa!=-1?1:0));
	REP(k,0,Adj[i].size()-1) { //放灯,放灯是一定可行的 
		int v=Adj[i][k];
		if(v!=fa) ans+=DP(v,1,i);
	}

	if(fa==-1||j==1) {   //不放灯
		int notPut=fa!=-1?1:0;  //+c;
		REP(k,0,Adj[i].size()-1){  
			int v=Adj[i][k];
			if(v!=fa) notPut+=DP(v,0,i);  
		}
		ans=min(ans,notPut);
	}

	return ans;  //放和不放取x最小
}
int main(int argc, char const *argv[])
{
	int T; scanf("%d",&T);
	while(T--){
		int n,m;
		scanf("%d%d",&n,&m);
		REP(i,0,n) Adj[i].clear();
		REP(i,1,m){
			int u,v; scanf("%d%d",&u,&v);
			Adj[u].push_back(v);
			Adj[v].push_back(u);
		}
		
		memset(vis,false,sizeof(vis));
		int ans=0;
		REP(i,0,n-1) if(!vis[i][0]) ans+=DP(i,0,-1);
		printf("%d %d %d\n", ans/M,m-ans%M,ans%M);
	}
	return 0;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值