HDU5627--Clarke and MST (bfs+位运算)
http://www.cnblogs.com/wenruo/p/5188495.html
Clarke and MST
Time Limit: 2000/1000 MS (Java/Others)
Memory Limit: 65536/65536 K (Java/Others)
问题描述
克拉克是一名人格分裂患者。某一天克拉克变成了一名图论研究者。
他学习了最小生成树的几个算法,于是突发奇想,想做一个位运算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; const int N = 600005; struct Edge { int to; int next; int w; } edge[N]; int head[N]; int cnt_edge; void add_edge(int u, int v, int w) { edge[cnt_edge].to = v; edge[cnt_edge].w = w; edge[cnt_edge].next = head[u]; head[u] = cnt_edge++; } bool vis_p[N]; int n, m; bool bfs(int __) //命名什么的不要在意orz { queue<int> q; clr(vis_p, false); q.push(1); vis_p[1] = true; while (!q.empty()) { int u = q.front(); q.pop(); for (int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].to; int w = edge[i].w; if (!vis_p[v] && (w & __) == __) { vis_p[v] = true; q.push(v); } } } for (int i = 1; i <= n; ++i) { if (!vis_p[i]) return false; } return true; } int main() { std::ios::sync_with_stdio(false); int t; cin >> t; while (t--) { cin >> n >> m; cnt_edge = 0; clr(head, -1); int x, y, w; for (int i = 0; i < m; ++i) { cin >> x >> y >> w; add_edge(x, y, w); add_edge(y, x, w); } int ans = 0; for (int i = 30; i >= 0; --i) { int now = (1 << i); if (bfs(now | ans)) ans = now | ans; } cout << ans << endl; } return 0; }
数组开小了超时到死啊,简直怀疑人生怀疑世界了……