HDU 4340

如题,一个比较裸的dp
注意dp的过程是从叶子节点开始向根节点dp
还有一个注意点是加边的过程

难点应该还是状态转移方程

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <math.h>
using namespace std;
#define N 105
#define INF 1<<30
int dp[N][2][2];//dp[i][j][k] k=0代表i点边上有用j攻占过的城市  此时dp[u][j][]=j[i]/2
int a[N],b[N],g[N][N]; // g[i][j]  代表i点连接的第j个点的编号 g[i][0]代表i节点的度数
inline int min(int a,int b){return a>b?b:a;}
inline void addedge(const int &u, const int &v)  
{  
    g[u][++g[u][0]] = v;  
}  
void dfs(int u,int father)
{
if(g[u][0]==1 && father!= -1)//是叶子节点[ father!=-1:排除根节点 (有可能根节点的出度也是1)]
{
dp[u][0][0] = a[u]/2;
dp[u][1][0] = b[u]/2;
dp[u][0][1] = a[u];
dp[u][1][1] = b[u];
}
else 
{
int sa=0,sb=0;//u点下面的子树的值
int da=INF,db=INF;
for(int i=1;i<=g[u][0];i++)
{
int v=g[u][i];//u点向下连接的所有的点
if(v!=father)//不是过来的那个点(即 不是u 的父节点)
{
dfs(v,u);//一直搜到叶子节点
sa += min(dp[v][0][0], dp[v][1][1]);  //v这点用A打 
                sb += min(dp[v][1][0], dp[v][0][1]);  //v这点用B打
                da = min(da, dp[v][0][1] - min(dp[v][0][0], dp[v][1][1]));  
                db = min(db, dp[v][1][1] - min(dp[v][1][0], dp[v][0][1]));  
            }
        }
        dp[u][0][0] = sa + (a[u] >> 1);//打u的军队和打v的军队都是A
        dp[u][1][0] = sb + (b[u] >> 1);  
        dp[u][0][1] = min(sa + a[u], sa + (a[u] >> 1) + da);  //u这点用a打和不用a打
        dp[u][1][1] = min(sb + b[u], sb + (b[u] >> 1) + db);  
    }
}
int main()
{
int n,i;
while(cin>>n){
for(i=1;i<=n;i++)cin>>a[i];
for(i=1;i<=n;i++)cin>>b[i];
memset(g,0,sizeof(g));
for(i=1;i<n;i++)
{
int u,v;cin>>u>>v;
addedge(u,v);
addedge(v,u);
}
memset(dp,0,sizeof(dp));
dfs(1,-1);
cout<<min(dp[1][0][1],dp[1][1][1])<<endl;
}
return 0;
}

http://blog.csdn.net/cyberzhg/article/details/7840922

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值