[BZOJ1596] [Usaco2008 Jan]电话网络(树形DP || 贪心)

传送门

1.树形DP

#include <cstdio>
#include <cstring>
#include <iostream>
#define N 10001

using namespace std;

int n, cnt;
int f[N][3], head[N], to[N << 1], next[N << 1];
bool vis[N];
//f[i][0]表示当前子树全选中,且根节点有放
//f[i][1]表示当前子树全选中,但根节点没放
//f[i][2]表示除了根节点以外,子树全选中 

inline int read()
{
	int x = 0, f = 1;
	char ch = getchar();
	for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
	for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0';
	return x * f;
}

inline void add(int x, int y)
{
	to[cnt] = y;
	next[cnt] = head[x];
	head[x] = cnt++;
}

inline void dfs(int u, int fa)
{
	int i, v, flag = 0, falg = 0, tmp = 23333333;
	f[u][0] = vis[u] = 1;
	for(i = head[u]; ~i; i = next[i])
	{
		v = to[i];
		if(!vis[v])
		{
			dfs(v, u);
			flag = 1;
			f[u][0] += min(f[v][0], min(f[v][1], f[v][2]));
			if(f[v][0] <= f[v][1])
			{
				f[u][1] += f[v][0];
				falg = 1;
			}
			else f[u][1] += f[v][1];
			f[u][2] += f[v][1];
		}
	}
	if(!falg)
	{
		for(i = head[u]; i ^ -1; i = next[i])
		{
			v = to[i];
			if(v != fa)
				tmp = min(tmp, f[u][1] - f[v][1] + f[v][0]);
		}
		f[u][1] = tmp;
	}
	if(!flag) f[u][1] = 23333333;
}

int main()
{
	int i, x, y;
	n = read();
	memset(head, -1, sizeof(head));
	for(i = 1; i < n; i++)
	{
		x = read();
		y = read();
		add(x, y);
		add(y, x);
	}
	dfs(1, 0);
	printf("%d
", min(f[1][0], f[1][1]));
	return 0; 
}

 

2.贪心

如果一个点的孩子节点或父亲节点有放,那么这个点就不用放了,如果这个点的儿子节点都没放,并且这个点和父亲节点也没放,那么就放在父节点上,ans++

#include <cstdio>
#include <cstring>
#include <iostream>
#define N 10001

using namespace std;

int n, cnt, ans;
int head[N], to[N << 1], next[N << 1];
bool vis[N], f[N];

inline int read()
{
	int x = 0, f = 1;
	char ch = getchar();
	for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
	for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0';
	return x * f;
}

inline void add(int x, int y)
{
	to[cnt] = y;
	next[cnt] = head[x];
	head[x] = cnt++;
}

inline void dfs(int u, int fa)
{
	int i, v, flag = 0;
	//flag判断是否有儿子被覆盖 
	vis[u] = 1;
	for(i = head[u]; ~i; i = next[i])
	{
		v = to[i];
		if(!vis[v])
		{
			dfs(v, u);
			if(f[v]) flag = 1;
		}
	}
	if(!flag && !f[u] && !f[fa]) f[fa] = 1, ans++;
}

int main()
{
	int i, x, y;
	n = read();
	memset(head, -1, sizeof(head));
	for(i = 1; i < n; i++)
	{
		x = read();
		y = read();
		add(x, y);
		add(y, x);
	}
	dfs(1, 0);
	printf("%d
", ans);
	return 0; 
}

  

原文地址:https://www.cnblogs.com/zhenghaotian/p/7552443.html