问题基本上是我发现union-find方法的递归版本比迭代版本更快。
// the union find method - recursive
int find(int k) {
if(f[k] != k) f[k] = find(f[k]);
return f[k];
}
// the union find method - iterative
int find(int k){
while(f[k] != k) k = f[k];
return f[k];
}
问题的背景是:good or bad balance。
问题是我们有平衡,但我们不知道它的好坏。 我们有两种不同重量的物品,同一种物品的重量相同。我们将所有项目索引为1,2,3..n。然后我们随机挑选其中两个并权衡平衡。每个称量结果以x,u,v的形式表示,其中x是位指示符,0表示余额,1表示不平衡,而u和v是两个项目的索引。
如果余额不好,就会出现矛盾,比如我们是否有称重结果:
0 1 2
1 1 2
第1项和第2项在两项措施中有不同的关系,因此余额不好。 我需要编写一个程序来告诉最早可以确定余额不好或平衡良好的措施。
基本上,这是经典联合查找问题的变体。 我希望迭代的union-find方法可以带来更好的性能,但是当递归版本被接受时,我的时间限制超过了它。我想问为什么这个???
这是我算法的整个版本。
#include <iostream>
#include <vector>
using namespace std;
#define N 10009
int n, m;
int x,u,v;
vector<int> f(2*N+1,0);
// iterative
int find(int k) {
if(k!=f[k]) f[k] = find(f[k]);
return f[k];
}
// recursive
// int find(int k) {
// while(k!=f[k]) k=f[k];
// return f[k];
// }
int main(){
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int T; // T is number of test cases
cin >> T;
while(T--){
// n is number of items, m is number of measurements
cin >> n >> m;
f.resize(2*n+1);
for(int i = 0 ; i < 2*n+1; ++i){
f[i] =i;
}
bool flag = false;
int ans = 0;
int r1, r2;
for(int i = 1 ; i <= m ; ++i){
// x is weighing result, u and v are item id.
cin >> x >> u >> v;
if(flag) continue;
if(x == 0) {
// two items are balance
if(find(u) == find(v+n) || find(v) == find(u+n)){
flag = true;
ans = i;
continue;
}
r1 = find(u); r2 = find(v);f[r2] = r1;
r1 = find(u+n); r2= find(v+n); f[r2] = r1;
} else {
// two items are imbalance
if(find(u) == find(v)){
flag = true;
ans = i;
continue;
}
r1 = find(u); r2= find(v+n);f[r2]=r1;
r1 = find(v); r2 = find(u+n);f[r2]=r1;
}
}
if(flag){
cout << "sad" << endl;
cout << ans << endl;
} else
cout << "great" << endl;
}
return 0;
}
示例测试用例
2
4 5
0 1 3
1 2 4
0 1 4
0 3 4
0 1 2
2 2
0 1 2
1 1 2
答案 0 :(得分:2)
递归和迭代版本不会做同样的事情。递归版本将使用结果更新f[k]
,以便在随后的具有相同k
值的调用中找到最多一个递归调用的答案。如果已找到其中一个中间值,即使在初始调用时也可以观察到效果。
迭代版本不会更新f
数组,因此后续调用必须执行完整循环,直到找到答案。
优化器也可以内联一些递归,因此它不像首次出现那样递归。