UVA - 10859 Placing Lampposts

Posted D O Time

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UVA - 10859 Placing Lampposts相关的知识,希望对你有一定的参考价值。

Placing Lampposts

传送门:https://vjudge.net/problem/UVA-10859

题目大意:给你一片森林,要求你在一些节点上放上灯,一个点放灯能照亮与之相连的所有的边。问你最小化防止的灯数,在灯数相同的条件下,最大化两个点都有灯的边数。
题解:

  首先有一个套路,也是做了此题才知道的,很神奇啊。最小化灯的数量,我们设灯数为V1,把“最大化两个点都有灯的边数”转化为“最下化只有一个点有灯的边数”,设为V2,那么我们设Val=Eps*V1+V2。这样只要DP一个值就可以了。Eps设成一个足够大的值,保证Eps>sum{V2}。此题姑且设为2000。
  然后我们就可以DP了。树上求解最优解,此题为森林,转化为每棵树的答案相加就可以了。那么怎么DP呢?
  设状态DP[i]代表i节点与它的子树以及连向父亲的那一条边的最小的Val。每一个节点有放灯与不放灯两种状态,但是我们发现,父亲放不放灯会影响儿子放不放灯,那么我们再加上一维的状态:dp[i][0/1]代表代表i节点与它的子树以及连向父亲的那一条边的最小的Val,j=1为父亲放灯,j=0代表父亲不放灯。
考虑两种方案:
1.  i放灯:i放灯的话,对于其他的没有什么要求,所以dp[i][j]+=dp[son][1],dp[i][j]+=Eps。如果当前j==0,并且不是根节点,那么dp[i][j]++,因为到父亲的那一条边只有1个灯。
2.  i不放灯:i不放灯,转移就有限制条件了,必须父亲放灯,或者i为根节点,dp[i][1]+=dp[son][0],如果i不是根节点,那么还要++,同样的因为到父亲的那一条边只有1个灯。
  然后一边dfs一边DP就可以了。注意状态转移是错综复杂的,并不是单一的0->1或0->0,具体顺序见代码。
  条件1可以更新j=1和0的情况;条件2只能更新j=1的情况,但是在根节点也可以更新j=0的情况。

 1 #include<queue>
 2 #include<cstdio>
 3 #include<vector>
 4 #include<cstring>
 5 #include<iostream>
 6 #include<algorithm>
 7 #define RG register
 8 #define LL long long
 9 #define fre(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout);
10 using namespace std;
11 const int MAXN=5000,Eps=2000;
12 int n,num,m,Case,ans;
13 int dp[MAXN][2];
14 int head[MAXN],to[MAXN],Next[MAXN];
15 bool vis[MAXN];
16 void dfs(int u,int fa)
17 {
18    vis[u]=1;
19    int sum1=0,sum2=Eps;
20    for(int i=head[u];i;i=Next[i])
21       {
22          int v=to[i];
23          if(v==fa)continue;
24          dfs(v,u);
25          sum1+=dp[v][0];//不放灯
26          sum2+=dp[v][1];//放灯
27       }
28    if(fa!=0)sum1++;
29    dp[u][1]=sum1;
30    dp[u][1]=min(dp[u][1],sum2);//与放灯的再比较一下。
31    dp[u][0]=sum2;
32    if(fa!=0) dp[u][0]++;
33    if(fa==0)
34       dp[u][0]=min(dp[u][0],sum1);
35 }
36 void add(int f,int t)
37 {
38    Next[++num]=head[f];
39    to[num]=t;
40    head[f]=num;
41 }
42 int main()
43 {
44    scanf("%d",&Case);
45    while(Case--)
46       {
47          scanf("%d%d",&n,&m);
48          num=0;
49          memset(head,0,sizeof head);
50          memset(vis,0,sizeof vis);
51          memset(dp,0,sizeof dp);
52          for(int i=1,a,b;i<=m;i++)
53             {
54                scanf("%d%d",&a,&b);
55                a++,b++;
56                add(a,b); add(b,a);
57             }
58          ans=0;
59          for(int i=1;i<=n;i++)
60             if(!vis[i])
61                {
62                   dfs(i,0);
63                   ans+=min(dp[i][0],dp[i][1]);
64                }
65          printf("%d %d %d\n",ans/Eps,m-ans%Eps,ans%Eps);
66       }
67    return 0;
68 }

 

以上是关于UVA - 10859 Placing Lampposts的主要内容,如果未能解决你的问题,请参考以下文章

UVA 10859 - Placing Lampposts 树形DP取双优值

UVA10859Placing Lampposts

UVA10859 Placing Lampposts

UVA10859 Placing Lampposts

UVA 10859 Placing Lampposts

UVA-10859 Placing Lampposts