程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> uva 10859 Placing Lampposts (樹形dp)

uva 10859 Placing Lampposts (樹形dp)

編輯:C++入門知識

 

題目: 點擊打開鏈接

 

題目大意
給你一個n個點m條邊的無向無環圖,在盡量少的節點上放燈,使得所有邊都被照亮。每盞燈將照亮以它為一個端點的所有邊。

在燈的總數最小的前提下,被兩盞燈同時被照亮的邊數應該盡量大。

 

 

 

思路
這是LRJ《入門經典》上的例題。

這題教會了我一個很有用的技巧:有兩個所求的值要優化,比如讓a盡量小,b也盡量小

那麼可以轉化為讓 M*a+b盡量小,其中M應該是一個比“a的最大值和b的最小值之差”還要大的數

最終的答案為ans/M, ans%M

 


回到這題,要求放的燈總數最小,被兩盞燈同時照亮的邊數盡量大。

因為每條邊要麼被一盞燈照亮,要麼被兩盞燈照亮,所以可以轉換為:

求:放的燈總數量最少,被一盞燈照亮的邊數盡量少。

就可以變成球 M*a+b 的最小值,a為放置的燈數量,b為被一盞燈照的邊數

 

 

f[u][1]表示u點放燈時的整個子樹最小值
f[u][0]表示u點不放燈時的整個子樹最小值

如果u放,那麼u個子結點可以選擇放,也可以不放,選擇其中較小的值。如果選的是不照,就要增加一條只有一個燈照的邊

如果u不放,那麼其子結點就必須選擇要放,而且每條邊都只有一個燈照

 


下面的我的代碼和書上實現的不一樣,更簡潔

 




代碼
 /**========================================== *  
 This is a solution for ACM/ICPC problem * *  
 @source:uva-10859 Placing Lampposts *   
@type:  樹形dp *   @author: shuangde *  
 @blog: blog.csdn.net/shuangde800 *  
 @email: [email protected] *===========================================*/
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<queue>
#include<cmath>
#include<cstring>
using namespace std;
typedef long long int64;
const int INF = 0x3f3f3f3f;const int MAXN = 1010;
vector<int>adj[MAXN];
bool vis[MAXN];
int n, m;int f[MAXN][2];
const int M = 2000;void dfs(int u) {    vis[u] = true;  
  f[u][0] = 0; 
   f[u][1] = M;  
  for(int i = 0;
 i < adj[u].size(); ++i) {        int v = adj[u][i]; 
        if(vis[v]) continue;        dfs(v);  
      f[u][0] += f[v][1] + 1;  
      if (f[v][0] < f[v][1]) {            f[u][1] += f[v][0] + 1;  
      } else {            f[u][1] += f[v][1];      
  }     }}int main(){    int nCase;   
 scanf("%d", &nCase);   
 while(nCase--) {        scanf("%d%d", &n, &m);  
      for(int i = 0;
 i < n; ++i)             adj[i].clear();  
      for(int i = 0;
 i < m; ++i) {            int u, v;  
          scanf("%d%d", &u, &v);    
        adj[u].push_back(v);     
       adj[v].push_back(u);     
   }        memset(vis, 0, sizeof(vis));    
    int ans = 0;   
     for(int i = 0;
 i < n; ++i) if(!vis[i]){            dfs(i);  
          ans += min(f[i][0], f[i][1]);    
    }        printf("%d %d %d\n", ans/M, m-(ans%M), ans%M);  
  }    return 0;} 

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved