uva_10859_Placing Lampposts( 樹形DP )
来源:互联网 发布:淘宝订单交易风险保障 编辑:程序博客网 时间:2024/06/12 20:38
題意:在一個n個節點,m條邊的無向無環圖中的節點中放置街燈,一個結點放置街燈那麼與這個結點爲頂點的邊都被照亮,使得每條邊都有被照亮的最少放置街燈的前提下,使得被兩個街燈照亮的邊儘量的多分析:在這裏的被兩個燈照亮的邊儘量的多,變一下:使得被一個燈照亮的邊儘量少無向無環圖也就是森林, 對於求兩個變量的最小設一個等式: x = aM+c, 其中a是需要最少的燈,c是一個燈照亮的邊數量,目標就是使得x最小,因爲a = x/M, c = x%M狀態:d[i,j]表示以i爲root的子樹,i的parent街燈放置的情況 x的數值狀態轉移看Code比較清晰,不好敘述Code:#include <set>#include <map>#include <cmath>#include <ctime>#include <stack>#include <queue>#include <deque>#include <vector>#include <cstdio>#include <bitset>#include <cstdlib>#include <cstring>#include <algorithm>using namespace std;#define DIR 4#define DIM 2#define STATUS 2#define MAXM 1000 + 10#define MAXN 1000 + 10#define oo (~0u)>>1#define INF 0x3F3F3F3F#define REPI(i, s, e) for(int i = s; i <= e; i ++)#define REPD(i, e, s) for(int i = e; i >= s; i --)static const double EPS = 1e-5;vector<int> vertex[MAXN];int f[MAXN][STATUS], visit[MAXN][STATUS], M;inline int dp(int x, int y, int p){ if( visit[x][y] ) { return f[x][y]; } visit[x][y] = 1; // x put a light f[x][y] = M; for(int i = 0; i < vertex[x].size(); i ++) { int k = vertex[x][i]; if( k == p ) { continue; } f[x][y] += dp(k, 1, x); } if( p >= 0 && !y ) { f[x][y] += 1; } // x not put a light if( y || p < 0 ) { int tmp = 0; for(int i = 0; i < vertex[x].size(); i ++) { int k = vertex[x][i]; if( k == p ) { continue; } tmp += dp(k, 0, x); } if( p >= 0 ) { tmp += 1; } f[x][y] = min(f[x][y], tmp); } return f[x][y];}int main(int argc, char const *argv[]){#ifndef ONLINE_JUDGE freopen("test.in", "r", stdin);#endif int cas, n, m, u, v; M = 2000; scanf("%d", &cas); REPI(k, 1, cas) { scanf("%d %d", &n, &m); REPI(i, 0, n) { memset(visit[i], 0, sizeof(visit[i])); vertex[i].erase(vertex[i].begin(), vertex[i].end()); } REPI(i, 1, m) { scanf("%d %d", &u, &v); vertex[u].push_back(v); vertex[v].push_back(u); } int ans = 0; REPI(i, 0, n-1) { if( visit[i][1] ) { continue; } ans += dp(i, 1, -1); } printf("%d %d %d\n", ans/M, m-ans%M, ans%M); } return 0;}