UVa 1218 Perfect Service

题目链接:

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3659


#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;

#define inf (1<<30)
// next[i]代表节点i的子节点
vector<int> next[10010];
// adj[i]代表节点i的相邻节点
vector<int> adj[10010];

// visit[i] = 1/0代表该点是否被遍历过
int visit[10010];

// record[i][0/1]代表以i为根不选/选i的最小完美点覆盖的点个数
int record[10010][2];

int get_min(int x, int f);
void dfs_search(int x);

int n;

int main()
{
	while(1)
	{
		scanf("%d", &n);
		memset(record, -1, sizeof(record));
		memset(visit, 0, sizeof(visit));
		for(int i = 1; i <= n; i++)
		{
			next[i] = vector<int>();
			adj[i] = vector<int>();
		}
		// 读入情况
		for(int i = 1; i <= n-1; i++)
		{
			int x, y;
			scanf("%d %d", &x, &y);
	
			adj[x].push_back(y);
			adj[y].push_back(x);

					
		}	
		// 建立树
		dfs_search(1);
/*
		for(int i = 1; i <= n; i++)
		{
			printf("%d: ", i);
			for(int j = 0; j < next[i].size(); j++)
				printf("%d ", next[i][j]);
			printf("\n");
		}	
*/		// 计算结果	
		printf("%d\n", min(get_min(1, 0), get_min(1, 1)));

		int x;
		scanf("%d", &x);

		if(x == -1)
			break;		
	}	
	return 0;
}

// 建立树
void dfs_search(int x)
{
	visit[x] = 1;
	for(int i = 0; i < adj[x].size(); i++)
	{
		if(visit[adj[x][i]] == 0)
		{
			next[x].push_back(adj[x][i]);
			dfs_search(adj[x][i]);
		}
	}	
}



// 计算结果record[x][f];
int get_min(int x, int f)
{
	if(record[x][f] != -1)
		return record[x][f];

	// 如果是叶子节点
	if(next[x].size() == 0)
	{
		// 如果不选该点,那么最小覆盖点个数为无穷大
		if(f == 0)
			record[x][f] = inf;
		// 选该点,最小覆盖点个数为1
		else
			record[x][f] = 1;
		return record[x][f];				
	}	

	// 如果不是叶子节点

	// 如果不选该点, 需要从子节点中选一个,其他子节点不选
	if(f == 0)
	{
		int not_sum = 0;
		// 统计子节点均不选的总数
		int must_count = 0;
		int must_num = 0;
		for(int i = 0; i < next[x].size(); i++)
		{
			int val = get_min(next[x][i], 0);
			if(val == inf)
			{
				must_count++;
				must_num = next[x][i];
			}
			else
				not_sum += val;
		}
		// 如果必须选的子节点数超过1个,那么该点的最小覆盖为不可能,无穷大
		if(must_count >= 2)
		{
			record[x][f] = inf;
		}
		// 如果必须选的子节点为1个,如果可选就选该子节点,其他子节点不选
		else if(must_count == 1)
		{
			int val = get_min(must_num,1);
			if(val == inf)
				record[x][f] = inf;
			else
				record[x][f] = not_sum + val;	
		}
		// 如果没有必须选的子节点,就依次尝试可以选的子节点
		else
		{
			int min_num = inf;
			for(int i = 0; i < next[x].size(); i++)
			{
				int val = get_min(next[x][i], 1);
				if(val != inf)
				{
					int t_num = not_sum - get_min(next[x][i],0) + val;
					if(min_num > t_num)
						min_num = t_num;
				}
					
			}
			record[x][f] = min_num;
		}
	}			
	// 如果选该节点,那么针对每个儿子,选择(选儿子,不选儿子也不选孙子)的较小情况
	else
	{
		int sum = 1;
		for(int i = 0; i < next[x].size(); i++)
		{
			int v1 = get_min(next[x][i], 1);
			int s = next[x][i];
			int v2 = 0;
			for(int j = 0; j < next[s].size(); j++)
			{
				int this_v = get_min(next[s][j], 0);
				if(this_v == inf)
				{
					v2 = inf;
					break;
				}
				else
					v2 += this_v;
			}

			if(v1 == inf && v2 == inf)
			{
				sum = inf;
				break;
			}	
			else
			{
				sum += min(v1, v2);
			}	
		}
		record[x][f] = sum;	
	}	
	
	return record[x][f];	
}

这题类似于点覆盖,但又不一样,不妨叫完美覆盖。

需要2维状态来表示每个点较为方便

d(i, 0): 以i为根,不选i的完美覆盖的点个数 

d(i, 1): 以i为根,选i的完美覆盖的点个数

针对每个叶子节点:d(i, 1) = 1, d(i, 0) = inf (inf 为无穷大)

针对非叶子节点:

d(i, 0) = min( d(j,1) + sum(d(k,0) (k != j)) (k, j均为i的儿子)) 。 

不选i时,需要选定i的一个儿子,其他儿子则必须不能选。

d(i, 1) = sum(min( d(j, 1) , d(k,0) (k为j的儿子))) (j为i的儿子)

选i时,针对i的每个儿子j有两种情况:(1).选该儿子j (2).不选该儿子j,此时节点j的所有儿子也不能选。 这两种情况选择较小的那一种。

光伏储能虚拟同步发电机VSG并网仿真模型(Similink仿真实现)内容概要:本文档介绍了光伏储能虚拟同步发电机(VSG)并网仿真模型的Simulink实现方法,重点在于通过建立光伏储能系统与虚拟同步发电机相结合的仿真模型,模拟其在并网过程中的动态响应与控制特性。该模型借鉴了同步发电机的惯性和阻尼特性,提升了新能源并网系统的频率和电压支撑能力,增强了系统的稳定性与可控性。文档还提及相关电力系统仿真技术的应用,包括逆变器控制、储能配置、并网稳定性分析等,并提供了完整的Simulink仿真文件及技术支持资源链接,便于科研人员复现与二次开发。; 适合人群:电气工程、自动化、能源系统等相关专业的研究生、科研人员及从事新能源并网技术开发的工程师。; 使用场景及目标:①用于研究光伏储能系统在弱电网条件下的并网稳定性问题;②掌握虚拟同步发电机(VSG)控制策略的设计与仿真方法;③支持高水平论文(如EI/SCI)的模型复现与创新研究;④为微电网、智能电网中的分布式能源接入提供技术参考。; 阅读建议:建议结合提供的Simulink模型文件与文档说明逐步操作,重点关注VSG控制模块的参数设置与动态响应分析,同时可延伸学习文中提及的MPPT、储能管理、谐波分析等相关技术,以提升综合仿真能力。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值