<<  < 2013 - >  >>
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31




本人学习acm的时间不是不长,而是太短了。虽然高中有过一定的基础,但是那些对于大学生的竞赛来说还是远远不够呢。
说到dp,这是我的一个弱项,我觉得这个东西很难以理解,虽然dp题目几乎每场比赛都有哦。
今天做了一个多校赛的dp题。名字是Capturing a country。
题目的状态是这样表示的,
f[i][j][k]
i:城市编号
j:0表示A占领,1表示B占领
k:0表示占领的初始点在它的子树上,1表示不在。

这样的话,细想就得到了转移方程(虽然我是看了好久才慢慢地看懂)

有一点需要提示就是在算sumA的时候把所有子树不当做第一个入侵的点求和了,所以下一步当要考虑子树上存在第一个入侵的点的时候,要把相应的部分减出来。
上代码吧,挺容易懂的。

#i nclude <iostream>
#i nclude <cstdio>
#i nclude <cstring>
#define maxn 105
#define sup ~0U>>2
using namespace std;

int next[2*maxn],v[2*maxn],first[maxn],n,m,ui,vi,N;
int a[maxn],b[maxn],f[maxn][2][2];

void addedge(int uu,int vv)
{
    N++;
    v[N]=vv;
    next[N]=first[uu];
    first[uu]=N;
}

void dfs(int now,int fa)
{

        int sumA=0,sumB=0,minA=sup,minB=sup;
        for (int i=first[now]; i!=-1; i=next[i])
        {
            if (v[i]==fa) continue;
            int V=v[i];
            dfs(V,now);
            sumA+=min(f[V][0][0],f[V][1][1]);//如果V被A占领,那么叶子被A占领可以没有第一个入侵点,但如果被B占领的话一定包含第一个入侵的点。
            sumB+=min(f[V][1][0],f[V][0][1]);
            minA=min(minA,f[V][0][1]-min(f[V][0][0],f[V][1][1]));//第二个min的意思就是把那个部分多加的减出来,同时为保证最优性应该取最小
            minB=min(minB,f[V][1][1]-min(f[V][1][0],f[V][0][1]));
        }//这里不要考虑是否为最后一个叶子节点哦,看我前面的赋值就知道了。
        f[now][0][0]=sumA+a[now]/2;
        f[now][0][1]=sumA+min(a[now],a[now]/2+minA);//把A当做第一个入侵的点或者把A的叶子当做第一个入侵的点
        f[now][1][0]=sumB+b[now]/2;
        f[now][1][1]=sumB+min(b[now],b[now]/2+minB);
}

int main()
{
    while (scanf("%d",&n)!=EOF)
    {
        N=0;
        memset(first,-1,sizeof first);
        memset(f,0,sizeof f);
        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++)
        {
            scanf("%d%d",&ui,&vi);
            addedge(ui,vi);
            addedge(vi,ui);
        }
        dfs(1,-1);
        printf("%d\n",min(f[1][0][1],f[1][1][1]));//第一个点可能被A或B占领。
    }
    return 0;
}

  • 标签:DP 
  • 发表评论:
    天涯博客欢迎您!