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; }