P2016 战略游戏
这道题的城堡是一颗树
题中有
注意,某个士兵在一个结点上时,与该结点相连的所有边将都可以被了望到。
所以定义数组 f[i][1/0]表示的是节点i上放士兵或者不放士兵
根据题意,如果当前节点不放置士兵,那么它的子节点必须全部放置士兵,因为要满足士兵可以看到所有的边。
所以有 f[u][0]+=f[v][1] 其中v是u的子节点
如果当前节点放置士兵,它的子节点选不选已经不重要了(因为树形dp自下而上,上面的节点不需要考虑),所以 f[u][1]+=min(f[v][0],f[v][1])
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
#include<math.h>
#define ls (p<<1)
#define rs (p<<1|1)
#define mid (l+r)/2
#define over(i,s,t) for(register long long i=s;i<=t;++i)
#define lver(i,t,s) for(register long long i=t;i>=s;--i)
using namespace std;
typedef long long ll;//全用ll可能会MLE或者直接WA,试着改成int看会不会A
const ll N=4000;
const ll INF=1e9+9;
const ll mod=2147483647;
const double EPS=1e-10;//-10次方约等于趋近为0
const double Pi=3.1415926535897;
template<typename T>void read(T &x)
{
x=0;char ch=getchar();ll f=1;
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}x*=f;
}
struct node
{
ll v,nex;
}e[N];
ll head[N],cnt,n,m,k,x;
ll f[N][2];//二维的只需要0或1即可,开大了memset会超时
ll t,arr[N],rt;
inline void add(ll u,ll v)
{
e[++cnt].nex=head[u];
e[cnt].v=v;
head[u]=cnt;
}
inline void init()
{
memset(f,0,sizeof f);
memset(head,0,sizeof head);
memset(arr,0,sizeof arr);
cnt=0;
}
void dfs(ll u)
{
f[u][0]=0,f[u][1]=1;//站或不站,站则至少需要1名士兵
for(ll i=head[u];i;i=e[i].nex)
{
dfs(e[i].v);//往下遍历
f[u][0]+=f[e[i].v][1];//若不站则相邻的必须站有士兵
f[u][1]+=min(f[e[i].v][1],f[e[i].v][0]);
}
}
int main()
{
while(scanf("%lld",&n)!=EOF)
{
init();
over(j,1,n)
{
ll a,b;
scanf("%lld%lld",&a,&b);
over(i,1,b)
{
ll c;
scanf("%lld",&c);
arr[c]++;
add(a,c);//树是有向图
}
}
over(i,0,n)
{
if(!arr[i])//找根
{
rt=i;
break;
}
}
dfs(rt);
printf("%lld\n",min(f[rt][1],f[rt][0]));
}
return 0;
}
只有输入有些许的不同
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
#include<math.h>
#define ls (p<<1)
#define rs (p<<1|1)
#define mid (l+r)/2
#define over(i,s,t) for(register long long i=s;i<=t;++i)
#define lver(i,t,s) for(register long long i=t;i>=s;--i)
using namespace std;
typedef long long ll;//全用ll可能会MLE或者直接WA,试着改成int看会不会A
const ll N=4000;
const ll INF=1e9+9;
const ll mod=2147483647;
const double EPS=1e-10;//-10次方约等于趋近为0
const double Pi=3.1415926535897;
template<typename T>void read(T &x)
{
x=0;char ch=getchar();ll f=1;
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}x*=f;
}
struct node
{
ll v,nex;
}e[N];
ll head[N],cnt,n,m,k,x;
ll f[N][2];//二维的只需要0或1即可,开大了memset会超时
ll t,arr[N],rt;
inline void add(ll u,ll v)
{
e[++cnt].nex=head[u];
e[cnt].v=v;
head[u]=cnt;
}
inline void init()
{
memset(f,0,sizeof f);
memset(head,0,sizeof head);
memset(arr,0,sizeof arr);
cnt=0;
}
void dfs(ll u)
{
f[u][0]=0,f[u][1]=1;//站或不站,站则至少需要1名士兵
for(ll i=head[u];i;i=e[i].nex)
{
dfs(e[i].v);//往下遍历
f[u][0]+=f[e[i].v][1];//若不站则相邻的必须站有士兵
f[u][1]+=min(f[e[i].v][1],f[e[i].v][0]);
}
}
int main()
{
while(scanf("%lld",&n)!=EOF)
{
init();
over(j,1,n)
{
ll a,b;
scanf("%lld:(%lld)",&a,&b);
over(i,1,b)
{
ll c;
scanf("%lld",&c);
arr[c]++;
add(a,c);//树是有向图
}
}
over(i,0,n)
{
if(!arr[i])//找根
{
rt=i;
break;
}
}
dfs(rt);
printf("%lld\n",min(f[rt][1],f[rt][0]));
}
return 0;
}
注:如果您通过本文,有(qi)用(guai)的知识增加了,请您点个赞再离开,如果不嫌弃的话,点个关注再走吧,日更博主每天在线答疑 ! 当然,也非常欢迎您能在讨论区指出此文的不足处,作者会及时对文章加以修正 !如果有任何问题,欢迎评论,非常乐意为您解答!( •̀ ω •́ )✧