您的位置:首页 > 其它

POJ 3659 Cell Phone Network【最小支配集】

2012-08-06 10:03 274 查看
题意:有以个 有 N 个节点的树形地图,问在这些顶点上最少建多少个电话杆,可以使得所有顶点被覆盖到,一个节点如果建立了电话杆,那么和它直接相连的顶点也会被覆盖到。

分析:用最少的点覆盖所有的点,即为求最少支配集。 可以用树形DP。

① dp[r][0] += min(dp[i][0],dp[i][1],dp[i][2]) dp[r][0]表示在自 r 顶点自身建, 以 r 为根节点的树所需要的最少覆盖数。
② dp[r][1] += min(dp[i][0],dp[i][1]) dp[r][1]表示在r 的子节点建, 以 r 为根节点的树所需要的最少覆盖数。
③ dp[r][2] += min(dp[i][0],dp[i][1]) dp[r][2]表示在r 的父节点建, 以 r 为根节点的数所需要的最少覆盖数。

其中第 ② 个有 特殊情况需要考虑,即如果每次 min () 取得都是dp[i][1]的话,即 r 所有的子节点的都没有建电话杆的话,这样得出的结果就会有误差,可以在其中记录最小

的dp[i][0] 值和其对应的 dp[i][1] 值,最后在这个 i 上建电话杆,就能保证自己被覆盖到,且用的电话杆最少, 这时dp[r][1]+=dp[i][0]-dp[i][1] 即可。

#include<stdio.h>
#include<string.h>
#define clr(x)memset(x,0,sizeof(x))
int min(int a,int b)
{ return a<b?a:b; }
#define maxn 100005
#define INF 0x1f1f1f1f
struct node
{
int to;
int next;
}e[1000000];
int tot;
int head[maxn];
int dp[maxn][3];
void add(int s,int u)
{
e[tot].to=u;
e[tot].next=head[s];
head[s]=tot++;
}
// dp[r][0] = min(dp[i][0],dp[i][1],dp[i][2])自身建
// dp[r][1] = min(dp[i][0],dp[i][1]) 子节点建
// dp[r][2] = min(dp[i][0],dp[i][1]) 父节点建
int n;
int v[maxn];
void dfs(int r)
{
v[r]=1;
int i,k;
int flag=1,ff=1,mi=INF,t;
dp[r][0]=1;
for(i=head[r];i;i=e[i].next)
{
k=e[i].to;
if(!v[k])
{
flag=0;
dfs(k);
dp[r][0]+=min(dp[k][0],min(dp[k][1],dp[k][2]));
if(dp[k][1]>=dp[k][0])
{
ff=0;
dp[r][1]+=dp[k][0];
}
else
{
dp[r][1]+=dp[k][1];
if(dp[k][0]<mi)
{
mi=dp[k][0];
t=dp[k][1];
}
}
dp[r][2]+=min(dp[k][0],dp[k][1]);
}
}
if(ff)
dp[r][1]+=mi-t;
if(flag)
{
dp[r][0]=1;
dp[r][1]=INF;
dp[r][2]=0;
}
}
int main()
{
int a,b,i;
while(scanf("%d",&n)!=EOF)
{
tot=1;
clr(v);
clr(dp);
clr(head);
for(i=1;i<n;i++)
{
scanf("%d%d",&a,&b);
add(a,b);
add(b,a);
}
if(n==1)
{
printf("1\n");
continue;
}
dfs(1);
printf("%d\n",min(dp[1][0],dp[1][1]));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: