• 【树形DP】MZOJ_1063_士兵守卫


    本题也是这三天来在下写的几篇树形DP之一,但是不知道为什么洛谷上面老是unknown error,。。。直接去了UVa,说我编译错误。。。我在想是不是头文件的原因,于是被逼无奈,交了一道c89的代码。(结果后来还是CE了)

    我真他娘是B了狗了。。。

    所以,因为测试数据只过了我们学校的OJ(需要注册才可看题),我会担心有可能代码有问题,欢迎大家杀我祭天指正错误。


    题目描述[传送门]

    Bob特别喜欢战略游戏,但有时他不能尽快找到最优解,所以他就很伤心。现在他又有一个问题,他必须保卫一个中世纪的城市,这个城市的道路形成了一棵树。他需要在树的节点上放最少的士兵来观察所有的边。你能帮助他么?

    例如下图就只需要一个士兵放在1号节点。

    输入

    输入文件soldier.in中有多组数据,每组数据的第一行N表示点的个数。接下来N行每行格式如下

      x:(k) a1 a2 … ak(x为点的编号,k为与其相连的子节点个数,a1, a2, …, ak分别为子节点的编号)

    输出

    输出文件soldier.out,对于每组数据输出一行一个数,即最少士兵数。

    样例输入

    4
    0:(1) 1
    1:(2) 2 3
    2:(0)
    3:(0)
    5
    3:(3) 1 4 2
    1:(1) 0
    2:(0)
    0:(0)
    4:(0)
    

    样例输出

    1
    2

    提示

    0 < N<= 1500, 0
    <= x < N


    于是这是我写的第三篇关于树形DP的博客。我越来越熟悉这个美妙而不失简洁的算法。。。。然而选课你还是做不来hiahiahia

    让我们来简化分析一下:

    给定一个无向多叉树,一个节点可以影响和它直接连接的节点,那请问需要至少多少个节点才可以使所有节点都被影响?

    动规最重要是定义状态,一个好的状态可以让你的程序写起来更加容易。

    在这里我们规定:f[u][0/1]用于表示u号节点放士兵或者不放士兵时的最小士兵数。

    那这个时候我们就要想状态转移方程了

    要是u节点不放士兵,那必须至少有一条与之相邻的点放了士兵,要是放士兵,则可放可不放,很容易得出f[u][0]=f[u][0]+f[v][1];//v为一个与u相邻的点   f[u][1]=min(f[v][1],f[v][0])

    并且在最后不要忘了把f[u][1]给++。

    这样状态转移和定义出来了,那么答案就是min(f[root][0],f[root][1]);

    下面给出完整代码:

    #include<bits/stdc++.h>
    namespace Jason{
        inline void scan(int &x){
        int f=1;x=0;char s=getchar();
        while(s<'0' || s>'9'){if(s=='-') f=-1;s=getchar();}
        while(s>='0' && s<='9'){x=x*10+s-'0';s=getchar();}
        x*=f;
    }
        inline void print(int x){
            if(x<0){putchar('-');x=-x;}
            if(x>9)print(x/10);char s=x%10+'0';
            putchar(s);
        }
    struct Edge_B{
        int to,dis;
        Edge_B* nxt;
    Edge_B(int to=-1,int dis=-1,Edge_B* n=NULL){this->to=to,this->dis=dis,this->nxt=n;} 
    };
    }
    using namespace std;
    using namespace Jason;
    const int maxn=15000+5;
    //--------------------
    int n,m,cnt=0;
    struct Edge{
        int to,nxt;
    }edge[maxn<<1];int head[maxn];
    int f[maxn][2];
    //--------------------
    void add(int x,int y)
    {
        edge[++cnt].nxt=head[x];
        edge[cnt].to=y;
        head[x]=cnt;
    }
    
    void dp(int u,int fa)
    {
        for(int i=head[u];i!=-1;i=edge[i].nxt)
        {
            int v=edge[i].to;
            if(v==fa) continue;
            dp(v,u);
            f[u][0]+=f[v][1];
            f[u][1]+=min(f[v][0],f[v][1]);
        }
        f[u][1]++;
    }
    
    int main()
    {
        //freopen("in","r",stdin);
        int a,b,c;
        while(scanf("%d",&n)==1)
        {
            memset(head,-1,sizeof(head));
            memset(f,0,sizeof(f));
            for(int i=0;i<n;++i)
            {
                scanf("%d:(%d)",&a,&b);
            for(int i=0;i<b;++i) scanf("%d",&c),add(a,c),add(c,a);
            }
            dp(0,-1);
            print(min(f[0][1],f[0][0]));putchar('
    ');
        }
        return 0;
    }

     然而我还是不会选课。。。。。

  • 相关阅读:
    命名函数
    匿名函数
    Elixir基础
    Elixir特性
    linux下安装erlang
    更具先序、中序遍历生成二叉树
    第一章 TCP/IP协议族
    React Native开发之expo中camera的基本使用
    Vue中异步组件(结合webpack,转载)
    vue中将html字符串转换成html后的一些问题
  • 原文地址:https://www.cnblogs.com/JasonY1337357025/p/10299340.html
Copyright © 2020-2023  润新知