问题描述
小李很喜欢玩计算机游戏,特别是战略游戏,但是有时他不能尽快找到解所以常常感到很沮丧。现在面临如下问题:他必须在一个中世纪的城堡里设防,城堡里的道路形成一棵无向树(连通图)。要在结点上安排最少的士兵使得他们可以看到所有边。你能帮助他吗?
你的任务是给出士兵的最少数目。
输入格式
输入包含多组数据。每组数据表示一棵树,在每组数据中:
第一行是结点的数目。
接下来的几行,每行按如下格式描述一个结点:
结点标识符 : ( 道路的数目 ) 结点标识符1 结点标识符2 ...... 结点标识符
或者
结点标识符 : (0)
对于 n (0<n<=1500) 个结点,结点标识符是一个从 0 到 n - 1 的整数。每条边在测试用例中只出现一次。
输出格式
对于每组数据,各给出一个整数表示士兵的最少数目.
例如:
输入: (注意:由于显示问题,测试时请去掉"0: (1)”中冒号和左括号之间的空格。)
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
这道题是树形DP,但有个简单算法,优先删除所有孤立的点和度为1的点,然后在度为1点的父节点放置士兵,循环直到所有点都被删除
#include<stdio.h>
#include<string.h>
int n=0,i=0,j=0,k=0,dp[3000][3000],a[3000],a1=0,a2=0,a3=0,count=0;
int main()
{
while (scanf("%d",&n)!=EOF)
{
count=0;
memset(a,0,sizeof(a));
memset(dp,0,sizeof(dp));
for (i=0;i<n;i++)
{
scanf("%d:(%d)",&a1,&a2);
a[a1]=a[a1]+a2;
for (j=0;j<a2;j++)
{
scanf("%d",&a3);
dp[a1][a3]=1;
dp[a3][a1]=1;
a[a3]++;
}
}
int num=n;
while (num>0)
{
for (i=0;i<n;i++)
if (a[i]==1&&a[i]==0)//度为1的点和孤立的点删除
{
num--;
a[i]=0;
break;
}
for(j=0;j<n;j++)
if (dp[i][j]==1)
{
dp[i][j]=0;
dp[j][i]=0;
num--;
count++; //度为1的点的父亲结点放置士兵
a[j]=0;
for (k=0;k<n;k++)
if (dp[j][k]==1) //删除该点及叶子结点
{
if (a[k]==1)
{
num--;
a[k]=0;
dp[j][k]=0;
dp[k][j]=0;
}
else
{
a[k]--;
dp[j][k]=0;
dp[k][j]=0;
}
}
}
}
printf("%d\n",count);
}
return 0;
}