UVA 1218 带状态判断的树形Dp

刘汝佳在书上说了状态转移方程, 嗯是三道题中较难的就动手写了一下。。

发现有的状态是无效的, 就去看了刘汝佳的代码, 额使用极大值来表示。。

这里也可以特殊判断(比如我) -----用IMPOSSIBLE表示不可能。

AC代码。

#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <cstring>
#define maxn 10010
#define IMPOSSIBLE  -12345
using namespace std;
int head[maxn], skip[2*maxn], V[2*maxn], mem;
vector<int> sons[maxn], DFSquen;
//int p[maxn];
void dfs(int u, int fa) {
  DFSquen.push_back(u); //p[u] = fa;
  for(int i = head[u]; i != -1; i = skip[i]) {
    if(V[i] == fa) continue;
    sons[u].push_back(V[i]);
    dfs(V[i], u);
  }
}

int d[maxn][3], pos; 
int Get_answer() {
  return d[0][2] == IMPOSSIBLE ? 
    d[0][0] : min(d[0][0],d[0][2]) ;
}

int main() {
  int n;
  while(scanf("%d",&n) == 1) {
  	  mem = 0; int x,y; memset(head,-1,sizeof(head)) ;
  	  for(int i = 1; i < n; i++) {
  	    scanf("%d%d",&x,&y);
  	    x--; y--;
  	    V[mem] = y; skip[mem] = head[x]; head[x] = mem++;
  	    V[mem] = x; skip[mem] = head[y]; head[y] = mem++;
	  }
	  for(int i = 0; i < n+1; i++) sons[i].clear();
	  DFSquen.clear();
	  dfs(0,-1);
	for(int loop = DFSquen.size()-1; loop >=0; loop--) {
	  int j = DFSquen[loop];
	  if(sons[j].empty()) {
	    d[j][0] = 1; d[j][1] = 0; d[j][2] = IMPOSSIBLE;
	  }else {
	    int cnt = 0, k = sons[j].size(), lin;
	    d[j][0] = 1;
	    for(int o = 0; o < k; o++ ) {// if it is server
	      lin = sons[j][o];
	      if(d[lin][1] == IMPOSSIBLE)
	        d[j][0]+=d[lin][0];
	      else d[j][0] += min(d[lin][0],d[lin][1]);
		}
		d[j][1] = 0;
		for(int o = 0; o < k; o++) { // if it isn't server but its father is server
		  lin = sons[j][o];
		  if(d[lin][2] == IMPOSSIBLE) {
		    cnt++; pos = lin;
		  } else d[j][1]+=d[lin][2];
		}
		if(cnt > 1) d[j][2] = IMPOSSIBLE;
		else if(cnt == 1) d[j][2] = d[j][1] + d[pos][0];
		else {
		  d[j][2] = 1000000000;
		  for(int o = 0; o < k; o++) {
		    lin = sons[j][o];
		    d[j][2] = min(d[j][2], d[j][1] - d[lin][2] + d[lin][0]);
		  }
		}
		if(cnt) d[j][1] = IMPOSSIBLE;
	  }
	}
    scanf("%d",&n);
    printf("%d\n",Get_answer());
  }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值