icpc:problems:usaco22open_visits_s
problems | |
---|---|
名称 | Visits S |
题目编号 | USACO22OPEN_S1 |
题目链接 | luogu.com.cn/… |
来源 | USACO |
算法分类 | 基环树 |
难易程度 | 容易 |
Visits S
想法
读懂题目就会发现,题目中的P排列,其实是处理奶牛的顺序。
将每个奶牛用自身与想要到的点建边,建出的图为基环树。可以轻松发现在一个环里,无论如何排列,总会有一个牛是不能叫的。所以每个环取最小值不能叫。
代码实现
非递归版本:
#include<iostream> #include<cstring> #include<vector> using namespace std; const int N = 100010; int v[N], p[N]; long long int ans; bool vis[N], this_vis[N]; int main() { int n; cin >> n; for (int i = 1; i <= n; ++i) { cin >> v[i] >> p[i]; ans += p[i]; } for (int i = 1; i <= n; ++i) { if(!vis[i]) { memset(this_vis, false, sizeof(this_vis)); this_vis[i] = true; vis[i] = true; int temp = i; while(!this_vis[v[temp]] && !vis[v[temp]]) { temp = v[temp]; this_vis[temp] = true; vis[temp] = true; } if(this_vis[v[temp]]) { int mi = p[temp], t = v[temp]; do{ mi = min(mi, p[t]); t = v[t]; }while(t != temp); ans -= mi; } } } cout << ans; return 0; }
递归版本:
#include<iostream> #include<cstring> #include<vector> using namespace std; const int N = 100010; int v[N], p[N]; long long int ans; bool vis[N], this_vis[N]; void DFS(int x) { if(this_vis[ v[x] ]) { int mi = p[x], temp = v[x]; do{ mi = min(mi, p[temp]); temp = v[temp]; }while(temp != x); ans -= mi; return ; } if(vis[ v[x] ]) return ; vis[v[x]] = true; this_vis[v[x]] = true; DFS(v[x]); return ; } int main() { int n; cin >> n; for (int i = 1; i <= n; ++i) { cin >> v[i] >> p[i]; ans += p[i]; } for (int i = 1; i <= n; ++i) { if(!vis[i]) { memset(this_vis, false, sizeof(this_vis)); this_vis[i] = true; vis[i] = true; DFS(i); } } cout << ans; return 0; }
/app/www/public/data/pages/icpc/problems/usaco22open_visits_s.txt · 最后更改: 2023/02/09 09:57 由 温婕莺