http://www.cnblogs.com/wenruo/p/5188495.html
克拉克是一名人格分裂患者。某一天克拉克变成了一名图论研究者。
他学习了最小生成树的几个算法,于是突发奇想,想做一个位运算and的最大生成树。
一棵生成树是由n−1条边组成的,且n个点两两可达。一棵生成树的大小等于所有在生成树上的边的权值经过位运算and后得到的数。
现在他想找出最大的生成树。
第一行是一个整数T(1≤T≤5),表示数据组数。
每组数据第一行是两个整数n,m(1≤n,m≤300000),分别表示点个数和边个数。其中n,m>100000n, 的数据最多一组。
接下来m行,每行3个整数x,y,w(1≤x,y≤n,0≤w≤109)9??),表示x,yx, yx,y之间有一条大小为www的边。
每组数据输出一行一个数,表示答案。若不存在生成树,输出000。
1 4 5 1 2 5 1 3 3 1 4 2 2 3 1 3 4 7
1
题解:
我们贪心的从大到小枚举每一个位,如果一个位能取当且仅当所有权值这个位不为0的边能形成一棵生成树。是否能形成生成树我们简单的bfs一下就行了。
代码:
#include <bits/stdc++.h> #define clr(x,c) memset(x,c,sizeof(x)) using namespace std; int Scan() { int res = 0, flag = 0; char ch; if((ch = getchar()) == ‘-‘) flag = 1; else if(ch >= ‘0‘ && ch <= ‘9‘) res = ch - ‘0‘; while((ch = getchar()) >= ‘0‘ && ch <= ‘9‘) res = res * 10 + (ch - ‘0‘); return flag ? -res : res; } const int N = 300005; struct Edge { int to; int w; Edge(int to = 0, int w = 0) : to(to), w(w){} } edge[N]; vector<Edge> G[N]; bool vis[N]; int n, m; int now; bool bfs() { queue<int> q; clr(vis, false); q.push(1); vis[1] = true; while (!q.empty()) { int u = q.front(); q.pop(); for (unsigned i = 0; i < G[u].size(); ++i) { int v = G[u][i].to; int w = G[u][i].w; if (!vis[v] && (w & now) == now) { vis[v] = true; q.push(v); } } } for (int i = 1; i <= n; ++i) { if (!vis[i]) return false; } return true; } int main() { int t = Scan(); while (t--) { n = Scan(); m = Scan(); for (int i = 1; i <= n; ++i) G[i].clear(); int x, y, w; for (int i = 0; i < m; ++i) { x = Scan(); y = Scan(); w = Scan(); G[x].push_back(Edge(y, w)); G[y].push_back(Edge(x, w)); } int ans = 0; for (int i = 30; i >= 0; --i) { now = ((1 << i) | ans); if (bfs()) ans = now; } printf("%d\n", ans); } return 0; }
开始用链式前向星一直T啊,555~是我写挫了还是链式前向星本身比较慢………
HDU5627--Clarke and MST (bfs+位运算)
原文:http://www.cnblogs.com/wenruo/p/5188495.html