标签:style blog http color os io for ar art
这种深层递归的题还是要多多体会,只看一遍是不够的
题意:有一个森林,在若干个节点处放一盏灯,灯能照亮与节点邻接的边。要求:符合要求的放置的灯最少为多少,在灯数最少的前提下,一条边同时被两盏灯照亮的边数最多是多少。
因为边数为m,所以被两盏灯照亮的边数最多就等价于被一盏灯照亮的边数最少
因为题目中要求两个最优解,将x = Ma + c 作为最小化的目标,其中a为灯数,c为被一盏灯照亮的边数,M则是一个比较大的值,到底有多大呢?M要比c的理论上的最大值与最小值之差还要大。这样在比较x1 和 x1时,如果a1 > a2,则x1一定>x2,这样就的好处就是将两个变量的最优解变成了一个变量的最优解,而且保证了灯数最少的前提下再求边数的最优解。
书上的两种决策说的很清楚了,我不就再啰嗦了。
我感觉我有点消化不良,认真体会,认真体会。。
1 //#define LOCAL 2 #include <vector> 3 #include <cstdio> 4 #include <cstring> 5 #include <algorithm> 6 using namespace std; 7 8 const int maxn = 1000 + 10; 9 vector<int> adj[maxn]; 10 int vis[maxn][2], d[maxn][2], n, m; 11 12 int dp(int i, int j, int f) 13 { 14 if(vis[i][j]) return d[i][j]; 15 vis[i][j] = 1; 16 int& ans = d[i][j]; 17 //放灯总是没有问题的 18 ans = 2000; 19 for(int k = 0; k < adj[i].size(); ++k) 20 if(adj[i][k] != f) 21 ans += dp(adj[i][k], 1, i); 22 if(f >= 0 && j == 0) ++ans; 23 //考虑没放灯时的情况 24 if(f < 0 || j == 1) 25 { 26 int sum = 0; 27 for(int k = 0; k < adj[i].size(); ++k) 28 if(adj[i][k] != f) 29 sum += dp(adj[i][k], 0, i); 30 if(f >= 0) ++sum; 31 ans = min(ans, sum); 32 } 33 return ans; 34 } 35 36 int main(void) 37 { 38 #ifdef LOCAL 39 freopen("10859in.txt", "r", stdin); 40 #endif 41 42 int T; 43 scanf("%d", &T); 44 while(T--) 45 { 46 scanf("%d%d", &n, &m); 47 for(int i = 0; i < n; ++i) adj[i].clear(); 48 for(int i = 0; i < m; ++i) 49 { 50 int a, b; 51 scanf("%d%d", &a, &b); 52 adj[a].push_back(b); 53 adj[b].push_back(a); 54 } 55 memset(vis, 0, sizeof(vis)); 56 int ans = 0; 57 for(int i = 0; i < n; ++i) 58 if(!vis[i][0]) 59 ans += dp(i, 0, -1); 60 printf("%d %d %d\n", ans/2000, m-(ans%2000), ans%2000); 61 } 62 return 0; 63 }
标签:style blog http color os io for ar art
原文地址:http://www.cnblogs.com/AOQNRMGYXLMV/p/3934796.html