MZOJ 1063 士兵守卫

MZOJ 1063 士兵守卫

题目描述

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

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

输入

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

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

输出

对于每组数据输出一行一个数,即最少士兵数。

样例输入

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


这道题难在读入,最主要是又要输入冒号 “:” 又要输入括号“()”。

其实scanf可以轻松解决问题,scanf("%d:(%d)",&x,&m)即可,scanf明白你的意思,不用用其他花里胡哨的操作;

剩下的与战略游戏完全一致了,详见MZOJ 1127 && LuoGu P2016 战略游戏 

#include<bits/stdc++.h>
#define maxn 100000
using namespace std;

int k=0,head[maxn];
int f[maxn][2];
int ans=0;

struct node{
    int v,nxt;
}e[maxn<<1];

void adde(int u,int v){
    e[k].v=v;
    e[k].nxt=head[u];
    head[u]=k++;
} 

void dp(int u,int fa){
    f[u][0]=0;f[u][1]=1;
    for(int i=head[u];~i;i=e[i].nxt){
        int v=e[i].v;
        if (v==fa) continue;
        dp(v,u);
        f[u][0]+=f[v][1];
        f[u][1]+=min(f[v][0],f[v][1]);
    }
}

void init(){
    freopen("soldier.in.txt","r",stdin);
    //freopen("solider.txt","w",stdout);
}

void readdata(){
    int n,x,y,m;
    while(scanf("%d",&n)!=EOF){
        memset(head,-1,sizeof(head));
        for(int i=1;i<=n;i++){
            scanf("%d:(%d)",&x,&m);
            for(int j=1;j<=m;j++){
                scanf("%d",&y);
                adde(x,y);
                adde(y,x);
            }
        }
        dp(0,-1);
        printf("%d
",min(f[0][1],f[0][0]));
    }
}

int main(){
    //init();
    readdata();
    return 0;
}
原文地址:https://www.cnblogs.com/quietus/p/10299998.html