srm 583

来源:互联网 发布:淘宝网减肥药 编辑:程序博客网 时间:2024/05/23 01:24

500:最多50个点的一棵树,每条边代表一盏灯,有两种状态,开或关,还有两种属性,重要或者不重要

定义一种操作是选择一条路径,将路径上的边的开关状态取反。问最少需要多少次操作才能使得每条重要的边都处于开的状态。

显然,所有的不重要的边都可以合并起来,然后搞成一棵新的树,每条边都是重要的,然后再YY一下,每条已经开的边不需要被覆盖到了,因为取反后还是要取反回来的,这样跟不去取反是一样的,所以现在这棵树被拆分成了若干棵树,每棵树全是需要取反的边,根据奇偶性贪心取即可。

#include <cstdlib>#include <cctype>#include <cstring>#include <cstdio>#include <cmath>#include <algorithm>#include <vector>#include <string>#include <iostream>#include <sstream>#include <map>#include <set>#include <queue>#include <stack>#include <ctime>using namespace std;class TurnOnLamps{public:     int minimize(vector <int> roads, string initState, string isImportant);        };int fa[55];int g[55][55];int find(int x) {  return fa[x] == x ? x : find(fa[x]);}void Union(int x,int y) {  int fx = find(x);  int fy = find(y);  if(fx != fy) {    fa[fx] = fy;  }}bool vis[55];int n;int owe[55];int ans;void dfs(int u,int f,int state) {  vis[u] = true;  int cnt = 0, sum = 0;  for(int i = 1; i < n; i++) {    if(g[u][i] != -1 && !vis[i]) {      dfs(i, u, g[u][i]);      cnt ^= g[u][i];      sum += g[u][i];      if(g[u][i] == 0) {        ans += owe[i];      }    }  }  owe[u] = cnt;  ans += sum / 2;}int TurnOnLamps::minimize(vector <int> roads, string initState, string isImportant){  ans = 0;  memset(owe, 0, sizeof(owe));  for(int i = 0; i < 50; i++) fa[i] = i;  memset(g, -1, sizeof(g));  n = roads.size() + 1;  for(int i = 0; i < roads.size(); i++) {    int a = roads[i];    int b = i + 1;    if(isImportant[i] == '0') {      Union(a, b);    }   }  for(int i = 0; i < roads.size(); i++) {    int a = roads[i];    int b = i + 1;    int x = find(a);    int y = find(b);    if(x != y)  g[x][y] = g[y][x] = (initState[i] == '0' );  }  int root = find(0);  memset(vis, false, sizeof(vis));  dfs(root, -1, -1);  ans += owe[root];  return ans;}// Powered by FileEdit// Powered by TZTester 1.01 [25-Feb-2003]// Powered by CodeProcessor


0 0