Hrbust 1683/Hdu 4340 Alice和Bob的国家【树型Dp+思维】

351 篇文章 2 订阅

Alice和Bob的国家
Time Limit: 1000 MSMemory Limit: 32768 K
Total Submit: 20(7 users)Total Accepted: 4(4 users)Rating: Special Judge: No
Description
Alice和Bob想去一起占领国家,这个国家有n个城市,为了去占据城市i,Alice需要花费A[i]分钟占领它,
Bob需要花费B[i]分钟占领它。由于城市之间有相连关系,如果城市i和城市j是邻城。如果Alice已经占据了
城市i,那么Alice去占据城市j的时间就是A[j]/2。如果j和z也是邻城那么Alice去占据z的时间也是A[z]/2。
对于Bob是同样的。我们定义占据一个国家的时间就是指将这个国家的所有城市占领。现在我们想知道Alice
和Bob一起将这个国家占领所需要的最少时间。(如果一个国家被Alice就不需要被Bob占领了)。
题目保证一个城市到另一个城市有且只有一条道路。
Input
第一行是一个整数T代表测试数据组数
对于每组测试数据第一行是一个整数N(0<N<100)代表城市数量,第二行是N个整数代表A[1],A[2]...A[N]。
第三行是N个整数代表B[1],B[2]....B[N]。接下来N-1行,每行两个整数x,y(代表x和y相连)。
Output
对于每组测试数据,输出占领一个国家的最少时间。
Sample Input
1
3
1 2 5
3 8 1
1 2
1 3
Sample Output
3
Author
陈禹@HRBUST

思路(思路及代码参考自:http://blog.csdn.net/lvshubao1314/article/details/43529927):


求最优解,而且是在一棵树上,那么考虑树型Dp.

我们设定Dp【i】【2】【2】:

①Dp【i】【0】【0】:表示到点i,以点i为子树的根这个点是被A攻占并且其子树中不存在攻占起点(全价花费点)的最优解。

②Dp【i】【0】【1】:表示到点i,以点i为子树的根这个点是被A攻占并且其子树中存在攻占起点(全价花费点)的最优解。

③Dp【i】【1】【0】:表示到点i,以点i为子树的根这个点是被B攻占并且其子树中不存在攻占起点(全价花费点)的最优解。

④Dp【i】【1】【1】:表示到点i,以点i为子树的根这个点是被B攻占并且其子树中存在攻占起点(全价花费点)的最优解。


那么状态转移方程:


Dp【u】【0】【0】=a【u】/2+Σmin(Dp【v】【0】【0】,Dp【v】【1】【1】);

这里设定x1=Σmin(Dp【v】【0】【0】,Dp【v】【1】【1】);

Dp【u】【0】【1】有两种情况,一种是当前点u是全价花费点,或者是其子树的某一个点:

Dp【u】【0】【1】=Min(a【u】+x1,a【u】/2+x1+y1);

这里y1就是Dp【v】【0】【1】与min(Dp【v】【0】【0】,Dp【v】【1】【1】)的差值的最小值。

即y1=Min(dp【v】【0】【1】-min(Dp【v】【0】【0】,Dp【v】【1】【1】));

其实每一个差值都是一个半价点变成全价点的花费。这里取最小即最优。

 

另外Dp【u】【1】【0】和Dp【u】【1】【1】与上述同理。


Ac代码:


#include<stdio.h>
#include<string.h>
#include<vector>
using namespace std;
vector<int>mp[150];
int a[150];
int b[150];
int dp[150][2][2];
void Dfs(int u,int from)
{
    int flag=0;
    int x1=0,x2=0;
    int y1=0x3f3f3f3f,y2=0x3f3f3f3f;
    for(int i=0;i<mp[u].size();i++)
    {
        int v=mp[u][i];
        if(v==from)continue;
        Dfs(v,u);
        flag=1;
        x1+=min(dp[v][0][0],dp[v][1][1]);
        x2+=min(dp[v][1][0],dp[v][0][1]);
        y1=min(y1,dp[v][0][1]-min(dp[v][0][0],dp[v][1][1]));
        y2=min(y2,dp[v][1][1]-min(dp[v][1][0],dp[v][0][1]));
    }
    if(flag==0)
    {
        dp[u][0][0]=a[u]/2;
        dp[u][0][1]=a[u];
        dp[u][1][0]=b[u]/2;
        dp[u][1][1]=b[u];
        return;
    }
    dp[u][0][0]=a[u]/2+x1;
    dp[u][0][1]=min(a[u]+x1,a[u]/2+x1+y1);
    dp[u][1][0]=b[u]/2+x2;
    dp[u][1][1]=min(b[u]+x2,b[u]/2+x2+y2);
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n;
        scanf("%d",&n);
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        for(int i=1;i<=n;i++)scanf("%d",&b[i]);
        for(int i=1;i<=n;i++)mp[i].clear();
        for(int i=1;i<=n-1;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            mp[x].push_back(y);
            mp[y].push_back(x);
        }
        Dfs(1,-1);
        printf("%d\n",min(dp[1][0][1],dp[1][1][1]));
    }
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值