上面代码中,cat.jumps()方法是一个箭头函数,这是错误的。调用 cat.jumps()时,如果是普通函数,该方法内部的 this 指向 cat;如果写成上面那样的箭头函数,使得 this 指向全局对象,因此不会得到预期结果。这是因为对象不构成单独的作用域,导致 jumps 箭头函数定义时的作用域就是全局作用域。
如果对象的方法使用了取值函数(getter)和存值函数(setter),则 name 属性不是在该方法上面,而是该方法的属性的描述对象的 get 和 set 属性上面,返回值是方法名前加上 get 和 set。有两种特殊情况:bind 方法创造的函数,name 属性返回 bound 加上原函数的名字;Function 构造函数创造的函数,name 属性返回 anonymous。
#include<bits/stdc++.h> usingnamespace std; typedeflonglong ll; constdouble PI = acos(-1.0); constdouble eps = 1e-6; constint INF = 0x3f3f3f3f; intsolve(int n) { int factor = 2, cnt = 0; vector<int> a; while (n != 1) { if (n % factor != 0) { factor++; a.push_back(cnt); cnt = 0; } else { n = n / factor; cnt++; } } a.push_back(cnt);
int sum = 1; for (int i = 0; i < a.size(); i++) { sum *= (a[i] + 1); } return sum; } intmain() { std::ios::sync_with_stdio(false); freopen("data.in", "r", stdin); int n = 1; while (1) { int ret = solve(n); // cout << ret << endl;5 if (ret == 100) { cout << n << endl; break; } n++; } return0; }
constint maxn = 1e4 + 7; int vis[maxn]; int n, m; structedge { int from, to, w; edge(int from, int to, int w) { this->from = from; this->to = to; this->w = w; } booloperator<(const edge b) const { returnthis->w > b.w; } }; vector<edge> gra[maxn]; priority_queue<edge> pq; intprim() { int res = 0; int cnt = 0; memset(vis, 0, sizeof(vis)); vis[1] = 1; for (int i = 0; i < gra[1].size(); i++) { edge tmp = gra[1][i]; pq.push(tmp); } while (cnt < n - 1 && !pq.empty()) { edge top = pq.top(); pq.pop(); int to = top.to; if (!vis[to]) { res += top.w; cnt++; vis[to] = 1; for (int i = 0; i < gra[to].size(); i++) { edge tmp = gra[to][i]; if (!vis[tmp.to]) { pq.push(tmp); } } } } if (cnt != n - 1) { return-1; } else { return res; } } voidaddedge(int from, int to, int w) { gra[from].push_back(edge(from, to, w)); gra[to].push_back(edge(to, from, w)); }
次小生成树问题一般使用 prim 算法解决。设最小生成树的权值为 W,因为 prim 算法可以记录生成树路径,思想是在剩下的边集中尝试将每一条边 (u,v) 加入生成树中 ,此时必然可以构成一个环,此时要删除权值最大的一条边。可以用一个 max 数组记录路径 path(u,v) 上的权值最大值 max(u,v),那么最终的答案就是 min (W + w(u,v) - max(u,v) ),max(u,v)可以在循环过程中求得。
constint maxn = 1e4 + 7; int n, m; int pre[maxn]; int dis[maxn]; bool vis[maxn]; bool use[maxn][maxn]; // 最小生成树使用的边 int maxv[maxn][maxn]; // u->v中边权最大值 int cost[maxn][maxn]; // u->v的花费 inlineintprim(int s) { memset(vis, 0, sizeof vis); memset(use, 0, sizeof use); memset(maxv, 0, sizeof maxv); memset(dis, 0x3f, sizeof dis); dis[s] = 0; for (int i = 1; i <= n; i++) pre[i] = s; int res = 0; for (int j = 1; j <= n; ++j) { int u, minw = INF; for (int i = 1; i <= n; ++i) { if (!vis[i] && dis[i] < minw) { u = i, minw = dis[i]; } } if (minw == INF) return-1; // 不连通 res += dis[u]; vis[u] = 1; use[u][pre[u]] = use[pre[u]][u] = 1; for (int v = 1; v <= n; ++v) { if (vis[v]) { maxv[u][v] = maxv[v][u] = max(maxv[v][pre[u]], dis[u]); } if (!vis[v] && dis[v] > cost[u][v]) { dis[v] = cost[u][v], pre[v] = u; } } } return res; } inlineintsmst(int s) { // s:起点 ans:最小生成树的值 int res = INF, ans = prim(s); if (ans == -1) return-1; for (int i = 1; i <= n; ++i) for (int j = i + 1; j <= n; ++j) if (cost[i][j] != INF && !use[i][j]) // i->j有边且不在最小生成数里 res = min(res, ans + cost[i][j] - maxv[i][j]); return res == INF ? -1 : res; }
intmain() { freopen("data.in", "r", stdin); cin >> n >> m; for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { cost[i][j] = cost[j][i] = INF; } } for (int i = 0; i < m; i++) { int from, to, w; scanf("%d%d%d", &from, &to, &w); cost[from][to] = min(cost[from][to], w); cost[to][from] = min(cost[to][from], w); } cout << smst(1); }
Kruskal 的算法思想是,对于一个有 n 个点和 m 条边的无向图来说,先对其边按照权值按照从小到大的顺序进行排序。初始化一个并查集。每次取排好序的边集中权值最小的一条边,若这条边与已经选取的边不构成回路,那么将这条边加入到最终的生成树中,最终得到的生成树一定是最小生成树。回路的判断用并查集来实现。时间复杂度为 O(mlogm)
假设 Kruskal 算法对 n≤k 阶图适用,那么,在 k+1 阶图 G 中,我们把最短边的两个端点 a 和 b 做一个合并操作,即把 u 与 v 合为一个点 v’,把原来接在 u 和 v 的边都接到 v’上去,这样就能够得到一个 k 阶图 G’(u,v 的合并是 k+1 少一条边),G’最小生成树 T’可以用 Kruskal 算法得到。
我们证明 T’+{}是 G 的最小生成树。
用反证法,如果 T’+{}不是最小生成树,最小生成树是 T,即 W(T)})。显然 T 应该包含,否则,可以用加入到 T 中,形成一个环,删除环上原有的任意一条边,形成一棵更小权值的生成树。而 T-{},是 G'的生成树。所以 W(T-{})=W(T’),也就是 W(T)=W(T’)+W()=W(T’+{}),产生了矛盾。于是假设不成立,T’+{}是 G 的最小生成树,Kruskal 算法对 k+1 阶图也适用。
structedge { int from, to, w; } edges[maxn]; intcmp(edge a, edge b) { return a.w < b.w; } int n, m; int u[maxn]; intfind(int x) { return u[x] == x ? x : u[x] = find(u[x]); } voidmerge(int x, int y) { u[x] = y; }
intkk() { int res = 0; for (int i = 1; i <= n; i++) { u[i] = i; }
sort(edges, edges + m, cmp); for (int i = 0; i < m; i++) { int x = find(edges[i].from); int y = find(edges[i].to); if (x != y) { merge(x, y); res += edges[i].w; } } return res; }
对于 KK 算法,求次小生成树的方法是维护一个子图集合和一个 maxw 数组,maxw 数据记录子图集之间的最大边权。开始每个点都属于一个子图。在进行并查集合并操作的时候合并子图。每次插入边的时候,更新边端点所在子图的最大边权为新加入的边的权值。显然根据 KK 算法的思想,每次加入的边的权值都是连接的两个子图中权值中最大的。
#include<bits/stdc++.h> usingnamespace std; typedeflonglong ll; constdouble PI = acos(-1.0); constdouble eps = 1e-6; constint INF = 0x3f3f3f3f; constint maxn = 2e5 + 7; vector<int> gra[maxn]; int maxw[5005][5005]; structedge { int from, to, w, vis; } edges[5005]; intcmp(edge &a, edge &b) { return a.w < b.w; } int n, m; int u[maxn]; intfind(int x) { return u[x] == x ? x : u[x] = find(u[x]); } voidmerge(int x, int y) { u[x] = y; for (int i = 0; i < gra[x].size(); i++) { gra[y].push_back(gra[x][i]); } }
intkk() { int res = 0; int cnt = 0; for (int i = 1; i <= n; i++) { u[i] = i; gra[i].push_back(i); }
sort(edges, edges + m, cmp); for (int i = 0; i < m; i++) { int x = find(edges[i].from); int y = find(edges[i].to); if (x != y) { for (int j = 0; j < gra[x].size(); j++) { for (int k = 0; k < gra[y].size(); k++) { maxw[gra[x][j]][gra[y][k]] = maxw[gra[y][k]][gra[x][j]] = edges[i].w; } } edges[i].vis = 1; merge(x, y); cnt++; res += edges[i].w; } }
if (cnt != n - 1) { return-1; } return res; }
intseckk() { int ans = INF; int res = kk(); if (res == -1) { return-1; } for (int i = 0; i < m; i++) { if (!edges[i].vis) { int w = edges[i].w; int wmax = maxw[edges[i].from][edges[i].to]; ans = min(ans, res + w - wmax); } } return ans; }
intmain() { freopen("data.in", "r", stdin); cin >> n >> m; for (int i = 0; i < m; i++) { scanf("%d%d%d", &edges[i].from, &edges[i].to, &edges[i].w); edges[i].vis = 0; } int res = seckk();