码迷,mamicode.com
首页 > 其他好文 > 详细

UVA - 10859 Placing Lampposts

时间:2017-10-13 23:53:59      阅读:425      评论:0      收藏:0      [点我收藏+]

标签:size   sts   oid   题解   logs   限制   eof   ios   mem   

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

标签:size   sts   oid   题解   logs   限制   eof   ios   mem   

原文地址:http://www.cnblogs.com/D-O-Time/p/7663692.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!