刘老师的代码似乎有误:
测试数据如下:
5
1 2
1 3
3 4
3 5
应该输出2,但是刘老师的代码是1,Uva上AC了…….
然后我去找了另一份网上的代码,输出是2,也AC了……
虽然新的这份代码也ac了,我的测试数据也过了,但是感觉思路还是有点问题(看作者思路似乎是允许一个非服务器点被多个服务器覆盖),修改了代码如下,也在Uva上AC了:
ps.我把自己不被子节点覆盖在注释中标为lon(loneliness),被其中一个子节点覆盖标为nei(neighbour),自己是服务器标记为ser(server)
#include<stdio.h>
#include<string.h>
#include<iostream>
// #include<Windows.h>
using namespace std;
#define INF 0x1f1f1f1f
int head[100000];
struct EdgeNode
{
int to;
int w;
int next;
}e[100000];
int cont;
int dp[5000000][3];
int vis[500000];
void add(int from,int to)
{
e[cont].to=to;
e[cont].next=head[from];
head[from]=cont++;
e[cont].to=from;
e[cont].next=head[to];
head[to]=cont++;
}
void Dp(int u)
{
dp[u][2]=0; // lon 自己是孤独的
dp[u][1]=0; // nei
dp[u][0]=1; // ser
int sum=0,inc=INF;
vis[u]=1;
bool judge=false; //是否有某个子节点被选中当做覆盖当前节点的服务器了
for(int k=head[u];k!=-1;k=e[k].next)
{
int to=e[k].to;
if(vis[to]==1)continue;
Dp(to);
dp[u][0]+=min(dp[to][0],dp[to][2]);
//这部分用来计算dp[u][1]的 dp[u][1]要求只有一个子节点是ser,其他都是lon
if (dp[to][1] == INF ) //说明这个点不能是lon的,所以就选中它是ser
{
if (!judge) //只能有一个子节点是ser,这个名额没有用完
{
dp[u][1] += dp[to][0];
judge = true;
}
else //如果有多个子节点不能是lon,就说明这种情况不可取,因为根节点要取min,这里就用inf代表它不可取
dp[u][1] = INF;
}
else
{
if (dp[u][1] != INF) { //先全部取子节点为lon,再选其中dp[to][0] - dp[to][1]最小的作为ser
dp[u][1] += dp[to][1];
inc = min(inc, dp[to][0] - dp[to][1]);
}
}
if(dp[to][1]!=INF&&dp[u][2]!=INF)dp[u][2]+=dp[to][1]; //如果有个子节点不存在 nei的情况 父节点自然不能有lon的情况
else dp[u][2]=INF;
}
if (dp[u][1] != INF && !judge)
dp[u][1] += inc;
}
int main()
{
int n;
while(~scanf("%d",&n))
{
memset(head,-1,sizeof(head));
memset(vis,0,sizeof(vis));
memset(dp,0,sizeof(dp));
cont=0;
for(int i=0;i<n-1;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
}
int op;
scanf("%d",&op);
Dp(1);
printf("%d\n",min(min(dp[1][0],dp[1][1]),dp[1][2]+1));
if(op==-1)break;
}
}