UVA10859 Placing Lampposts
Placing Lampposts
给你一个森林。选择一些点放灯,每个灯可以照亮所在点周围的所有边。优先最小化灯的数量,使所有边被照亮,然后最大化被两盏灯照亮的边的个数
由于 被两盏灯照亮的边的个数 + 被一盏灯照亮的边的个数 = 边数
把“最大化被两盏灯照亮的边的个数”转换为“最小化被一盏灯照亮的边的个数”
“若有两个变量v1,v2,最优化v1的前提下最优化v2,可以设置为最优化Mv1 + v2,M是一个比max(v2) - min(v2)大的数”.这样的话v1增加1,增加量就一定比v2增加量大了
然后常规树形dp即可
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <algorithm> 6 #include <queue> 7 #include <vector> 8 #define min(a, b) ((a) < (b) ? (a) : (b)) 9 #define max(a, b) ((a) > (b) ? (a) : (b)) 10 #define abs(a) ((a) < 0 ? (-1 * (a)) : (a)) 11 inline void swap(int &a, int &b) 12 { 13 int tmp = a;a = b;b = tmp; 14 } 15 inline void read(int &x) 16 { 17 x = 0;char ch = getchar(), c = ch; 18 while(ch < '0' || ch > '9') c = ch, ch = getchar(); 19 while(ch <= '9' && ch >= '0') x = x * 10 + ch - '0', ch = getchar(); 20 if(c == '-') x = -x; 21 } 22 23 const int INF = 0x3f3f3f3f; 24 const int MAXN = 10000 + 10; 25 const int K = 2000; 26 27 struct Edge 28 { 29 int u,v,nxt; 30 Edge(int _u, int _v, int _nxt){u = _u;v = _v;nxt = _nxt;} 31 Edge(){} 32 }edge[MAXN << 1]; 33 int head[MAXN], cnt; 34 inline void insert(int a, int b) 35 { 36 edge[++cnt] = Edge(a,b,head[a]); 37 head[a] = cnt; 38 } 39 40 int t,n,m,b[MAXN],ans,dp[MAXN][2],root; 41 42 //设x为被一盏灯照亮的边,y表示灯的数量,最小化Ky + x 43 //dp[i][0]表示第i个点的父亲不放灯,i子树中的边和i与父亲的边最小Ky + x 44 //dp[i][1]表示第i个点的父亲放灯,i子树中的边和i与父亲的边最小的Ky + x 45 46 void dfs(int x) 47 { 48 b[x] = 1; 49 int tmp1 = 0, tmp2 = 0, tmp3 = 0, tmp4 = 0; 50 for(register int pos = head[x];pos;pos = edge[pos].nxt) 51 { 52 int v = edge[pos].v; 53 if(!b[v]) dfs(v); 54 55 //dp[x][0]父节点不放灯 56 //这个点不放灯 57 if(root == x) tmp1 += dp[v][0]; 58 //这个点放灯 59 tmp2 += dp[v][1]; 60 61 //dp[x][1]父节点放灯 62 //这个点不放灯 63 tmp3 += dp[v][0]; 64 //这个点放灯 65 tmp4 += dp[v][1]; 66 } 67 tmp2 += K;tmp4 += K; 68 if(root != x) ++ tmp2, ++ tmp3, tmp1 = INF; 69 dp[x][0] = min(tmp1, tmp2); 70 dp[x][1] = min(tmp3, tmp4); 71 return; 72 } 73 74 int main() 75 { 76 read(t); 77 for(;t;--t) 78 { 79 read(n), read(m); 80 memset(b, 0, sizeof(b)); 81 memset(head, 0, sizeof(head)); 82 memset(dp, 0, sizeof(dp));ans = 0; 83 for(register int i = 1;i <= m;++ i) 84 { 85 int tmp1,tmp2;read(tmp1), read(tmp2); 86 ++ tmp1, ++ tmp2; 87 insert(tmp1, tmp2), insert(tmp2, tmp1); 88 } 89 for(register int i = 1;i <= n;++ i) 90 if(!b[i]) root = i, dfs(i), ans += dp[i][0]; 91 printf("%d %d %d\n", ans/K, m - ans%K, ans%K); 92 } 93 return 0; 94 }