每个节点上可以站士兵守卫道路。
问要守卫所有的道路至少要多少个士兵。
跟那个
poj 2342 Anniversary party(简单树形dp+dfs)
真是像极了。。。
我就是根据那个来写的。。。
思路如下:
如果当前节点站士兵,则以它为父亲的子节点(就是它的邻接点)就可以站或者不站,取
两种情况中消耗最小的。 dp[i][1]+=min(dp[v][1],dp[v][0])
如果当前节点不站士兵,则它的邻接点不能被守卫到,故它的邻接点必须要有士兵。
dp[i][0]+=dp[v][1];
v是i的邻接点。
吐槽一下啦+ +
hdu 数据比poj 弱。。。。我开始用vector写,poj 上死活都是mle
后来看了别人的提醒,改成邻接表存,就AC了。。。
加边的时候当无向边处理。所以不要忘了add(b,a)!!
邻接表版本yoha !
#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
using namespace std;
struct edge
{
int to;
int next;
}w[10010];
bool vis[1510];
int dp[1510][2],head[1510],tot;
void add(int x,int y)
{
w[tot].to=y;
w[tot].next=head[x];
head[x]=tot++;
}
void dfs(int r)
{
vis[r]=true;
int v,i;
for(i=head[r];i;i=w[i].next)
{
v=w[i].to;
if(!vis[v])
{
dfs(v);
dp[r][0]+=dp[v][1];
dp[r][1]+=min(dp[v][1],dp[v][0]);
}
}
}
int main()
{
int n,m,a,b;
while(scanf("%d",&n)!=EOF)
{
memset(vis,0,sizeof(vis));
memset(head,0,sizeof(head));
tot=1;
for(int i=0;i<n;i++)
{
dp[i][0]=0;
dp[i][1]=1;
}
for(int i=0;i<n;i++)
{
scanf("%d:(%d)",&a,&m);
for(int i=0;i<m;i++)
{
scanf("%d",&b);
add(a,b);
add(b,a);
}
}
dfs(0);
printf("%d\n",min(dp[0][0],dp[0][1]));
}
return 0;
}
只在hdu过的了的vector版本~~~~~= =
#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
using namespace std;
vector<int> t[1510];
bool vis[1510];
int dp[1510][2];
void dfs(int r)
{
vis[r]=true;
int v;
int s=t[r].size();
for(int i=0;i<s;i++)
{
v=t[r][i];
if(!vis[v])
{
dfs(v);
dp[r][0]+=dp[v][1];
dp[r][1]+=min(dp[v][1],dp[v][0]);
}
}
//dp[r][1]+=1;
}
int main()
{
int n,m,a,b;
while(scanf("%d",&n)!=EOF)
{
memset(t,0,sizeof(t));
memset(vis,0,sizeof(vis));
for(int i=0;i<n;i++)
t[i].clear();
for(int i=0;i<n;i++)
{
dp[i][0]=0;
dp[i][1]=1;
}
//memset(dp,0,sizeof(dp));
for(int i=0;i<n;i++)
{
scanf("%d:(%d)",&a,&m);
for(int i=0;i<m;i++)
{
scanf("%d",&b);
t[a].push_back(b);
t[b].push_back(a);
}
}
dfs(0);
printf("%d\n",min(dp[0][0],dp[0][1]));
}
return 0;
}