生活随笔
收集整理的這篇文章主要介紹了
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 }
?
轉載于:https://www.cnblogs.com/D-O-Time/p/7663692.html
總結
以上是生活随笔為你收集整理的UVA - 10859 Placing Lampposts 放置街灯的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。