defchange(self, root:int, l:int, r:int, delta:int) -> None: """ 作用: 区间修改 """ self.pushdown(root) if l == self.t[root].l and r == self.t[root].r: self.t[root].lazy += delta return mid = (self.t[root].l+self.t[root].r)>>1 ch = root<<1 if r <= mid: self.change(ch,l,r,delta) elif l > mid: self.change(ch+1,l,r,delta) else: self.change(ch,l,mid,delta) self.change(ch+1,mid+1,r,delta) self.update(root)
defquery_min(self, root:int, l:int, r:int) -> int: self.pushdown(root) if self.t[root].l == l and self.t[root].r == r: return self.t[root].min mid = (self.t[root].l+self.t[root].r) >> 1 ch = root<<1 if r <= mid: return self.query_min(ch,l,r) elif l > mid: return self.query_min(ch+1,l,r) else: returnmin(self.query_min(ch,l,mid),self.query_min(ch+1,mid+1,r))
数学python模板
快速幂
1 2 3 4 5 6 7 8 9 10 11
p = 998244353 deffastpow(a, n): base, res = a, 1 while n != 0: if n & 1: #取最后一位二进制数,看是否为1 res = res * base % p base = base * base % p n >>= 1 return res%p """自带的快速幂""" pow(a,b,p) # a^b mod p
classFactorial: def__init__(self, N, mod) -> None: self.mod = mod self.f = [1for _ inrange(N)] self.g = [1for _ inrange(N)] for i inrange(1, N): self.f[i] = self.f[i - 1] * i % self.mod self.g[-1] = pow(self.f[-1], mod - 2, mod) for i inrange(N - 2, -1, -1): self.g[i] = self.g[i + 1] * (i + 1) % self.mod defcomb(self, n, m): if n < 0or m < 0or n < m: return0 return self.f[n] * self.g[m] % self.mod * self.g[n - m] % self.mod defperm(self, n, m): if n < 0or m < 0or n < m: return0 return self.f[n] * self.g[n - m] % self.mod defcatalan(self, n): # TODO: check 2 * n < N# return (self.comb(2 * n, n) - self.comb(2 * n, n - 1)) % self.mod # N个不同的物品放进m个不同的集合,保证每个集合都不是空集# defsterling(self, n, m): if n < m: return0 else: res = 0 for i inrange(m + 1): t = self.comb(m, i) * pow(m - i, n, self.mod) % self.mod if i & 1: res -= t else: res += t res %= self.mod return res * self.g[m] % self.mod n,m = map(int,input().split()) t = Factorial(n+1,int(1e9) + 7) print(t.sterling(n,m))
1、质数
从 到 中有 个质数
(1) 判定(试除法)
1 2 3 4 5 6
defis_primer(n): i = 2 while i <= n // i: if n % i == 0: returnFalse i += 1 returnTrue
(2)分解质因数(试除法)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
primes,c = [],[] defdivide(n): i = 2 while i*i <= n: if n % i == 0: cnt = 0 while n % i == 0: n //= i cnt += 1 primes.append(i) # i 为质因数,cnt 为对应的指数 c.append(cnt) i += 1 if n > 1: primes.append(n) c.append(1)
如果有多次询问:当然可以预处理质数O(sqrt(n)),每次询问O(sqrt(n)/log(n))
(3)埃氏筛法
1 2 3 4 5 6 7
ls, primes = [0]*(n+1), [] defget_primes(n): for i inrange(2, int(sqrt(n))+1): ifnot ls[i]: primes.append(i) for j inrange(i+i, n+1, i): ls[j] = 1
for i inrange(2, MAXN): if is_prime[i]: prime.append(i) for j inrange(i*i, MAXN, i): is_prime[j] = 0 defsolve(): l, r = map(int, sys.stdin.readline().split()) if l == 1: l += 1#不处理的话,1会筛不掉 n = r - l + 1 if n < 2: return vis = [0] * n for p in prime: if p > r: break for i inrange((l+p-1)//p * p, r//p*p+1, p): if i == p: continue vis[i-l] = 1 ls = [] for i inrange(n): if vis[i]: continue ls.append(i)
(5)线性筛法(确保了每个被筛掉的合数都是由其最小质因子筛掉的)
当 时,由于我们是从小到大遍历质数,所以 是 的最小质因子,也是 的最小质因子。
当 时, 小于 的最小质因子,所以也是 的最小质因子。
1 2 3 4 5 6 7 8 9 10
N = 3*10**5 is_prime = [1]*(N+1) primes = [] for i inrange(2,N+1): if is_prime[i]: primes.append(i) j = 0 while primes[j] <= N//i: is_prime[primes[j]*i] = 0 if i % primes[j] == 0: break j += 1
2、约数
(1)扩展欧几里得算法
所以:
又 $a \mod b = a - a//bbax + by = b(x’ - a//by’) + ay’ = d$
即:
1 2 3 4
defexgcd(a, b): if b == 0: return [a, 1, 0] [g, x, y] = exgcd(b, a % b) return [g, y, x - a // b * y]
ex_gcd解方程技巧
假设 ax+by = (a,b) 的一组解为,则通解为:,
有解当且仅当 ,特解为
假设要解方程 ,只要 互为质数,那么解出来 后再乘个 就是上述方程的解
3、同余与模
判定在 里 a 是否有逆元
如果有如何求解逆元
考虑 有解,当且仅当 互质,如果 为质数,则 ~ 在模 的情况下有逆。
欧拉定理
如果 ,那么 ,其中 是欧拉函数。
费马小定理
乘法逆元的三种求法
扩展欧几里得算法:,已知 求
欧拉定理:设 为正整数, 且 ,
费马小定理:当模数 为质数时 即为 的乘法逆元
求 ~ (对于质数 的逆元):
1 2 3 4
inv = [0]*(n+1) inv[1] = 1 for i inrange(2,n+1): inv[i] = (-inv[p%i]*(p//i)) % p
n,m = map(int,input().split()) head = [0]*(n+1) ver,edge,nxt = [0]*(2*m+1),[0]*(2*m+1),[0]*(2*m+1) tot = 1#为异或求反向边做铺垫
defadd(x, y, z): global tot tot += 1 ver[tot], edge[tot] = y, z nxt[tot], head[x] = head[x], tot
# 遍历 x 的出边 i = head[x] while i: y,z = ver[i],edge[i] i = nxt[i]
z = edge[i^1] """存的是edge[i] 的反向边"""
有向无环图拓扑排序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
g = {i:[] for i inrange(1,n+1)} deg = [0]*(n+1) #记录入度 for _ inrange(m): u,v,w = map(int, sys.stdin.readline().split()) g[u].append((v,w)) deg[v] += 1 ls, ans = [], [] q = deque() for i inrange(1,n+1): if deg[i] == 0: q.append(i) while q: x = q.popleft() for y,w in g[x]: deg[y]-=1 if deg[y] == 0: q.append(y)
n,m = map(int, sys.stdin.readline().split()) c,u,deg = [0]*(n+1), [0]*(n+1), [0]*(n+1) g = {i:[] for i inrange(1,n+1)} for i inrange(1,n+1): c[i],u[i] = map(int, sys.stdin.readline().split()) if c[i] == 0: c[i] -= u[i] for _ inrange(m): x,y,z = map(int, sys.stdin.readline().split()) g[x].append((y,z)) deg[y] += 1
q = deque() for i inrange(1,n+1): if deg[i] == 0: q.append(i) while q: x = q.popleft() for y,w in g[x]: deg[y] -= 1 c[y] += w*c[x] if c[x] > 0else0 if deg[y] == 0: q.append(y) flag = True for i inrange(1,n+1): iflen(g[i]) == 0and c[i] > 0: print(i,c[i]) flag = False if flag: print("NULL")
t = int(sys.stdin.readline()) while t > 0: t -= 1 n,m = map(int, sys.stdin.readline().split()) g = {i:[] for i inrange(1,n+1)} deg = [0]*(n+1) for _ inrange(m): x,y = map(int, sys. stdin.readline().split()) g[y].append(x) deg[x] += 1 ans, q = [], [] for i inrange(1,n+1): if deg[i] == 0: heapq.heappush(q,-i) # 入度为0 表示没有限制 i 必须得在哪个前面做, 所以应该是每个连通块中最后做的 while q: x = -heapq.heappop(q) # 先处理最大的度为0的点, 让其最后做 ans.append(x) for y in g[x]: #遍历需要在 x 前做的点 deg[y] -= 1 if deg[y] == 0: heapq.heappush(q,-y) #继续保持最大的在前面 iflen(ans) == n: print(*ans[::-1]) else: print("Impossible!")
1、最短路模板
堆优化Dijkstra:
1 2 3 4 5 6 7 8 9 10 11 12 13
defdijkstra(r = 1): heap = [] # 小顶堆实现优先队列 dist[r] = 0 heapq.heappush(heap, (0, r)) while heap: start = heapq.heappop(heap) if vis[start[1]]: continue vis[start[1]] = True for i in g[start[1]]: # 根据现找到的点start【1】更新其相连点的权重 if dist[i[0]] > dist[start[1]] + i[1]: # 判断是否松弛 dist[i[0]] = dist[start[1]] + i[1] # 松弛边 heapq.heappush(heap, (dist[i[0]], i[0])) # 将松弛过的新边权值加入堆 return dist[n]
朴素Dijkstra用于稠密图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
g = [[inf if i != j else0for i inrange(N)] for j inrange(N)] #groph st = [0for _ inrange(N)] dist = [inf for _ inrange(N)]
defdijkstra(): """朴素dijkstra算法 O(n^2)用于稠密图""" dist[1] = 0 for i inrange(n): t = -1 for j inrange(1, n+1): ifnot st[j] and (t == -1or dist[t] > dist[j]): t = j st[t] = 1 for j inrange(1, n+1): dist[j] = min(dist[j], dist[t] + g[t][j]) return dist[n]
n,m = map(int, sys.stdin.readline().split()) g = {i:[] for i inrange(1, n+1)} for _ inrange(m): u,v,w = map(int, sys.stdin.readline().split()) g[u].append((v, w)) inf = float("inf") dist = [inf for _ inrange(n+1)] pi = [i for i inrange(n+1)] #记录最短路径树,记录该结点的前驱结点 defbellman_ford(G, r = 1): dist[r] = 0 for j inrange(1,n): for i inrange(1, n+1): #遍历所有边 for x in G[i]: if dist[x[0]] > dist[i] + x[1]: dist[x[0]] = dist[i] + x[1] pi[x[0]] = i for i inrange(1, n+1): for v,w in G[i]: if dist[v] > dist[i] + w: returnFalse returnTrue bellman_ford(g) print(dist[n])
deffloyd(w): """Floyd算法求所有结点对的最短路径,时间复杂度:O(V^3)""" d = deepcopy(w) for k inrange(1, n+1): for i inrange(1,n+1): for j inrange(1,n+1): d[i][j] = min(d[i][j], d[i][k] + d[k][j]) return d
"""Floyd求传递闭包""" inf = float("inf") n,m = map(int, sys.stdin.readline().split()) g = [[0]*(n+1) for _ inrange(n+1)] for i inrange(m): x,y = map(int, sys.stdin.readline().split()) g[x][y] = 1
deffloyd(): for k inrange(1,n+1): for x inrange(1,n+1): for y inrange(1,n+1): g[x][y] |= g[x][k] & g[k][y]
defdijkstra(r = 1): q = [] dist[r][0] = 0 heapq.heappush(q, (0, r, 0)) # (d, 点的编号, 第几层) 不同的层数代表免费几条边 while q: x,i,j = heapq.heappop(q) if vis[i][j]: continue vis[i][j] = True for v,w in g[i]: if dist[v][j] > max(x, w): dist[v][j] = max(x, w) heapq.heappush(q, (dist[v][j], v, j)) if j < k and dist[v][j+1] > x: dist[v][j+1] = dist[i][j] heapq.heappush(q, (dist[v][j+1], v, j+1))
dijkstra(1) ans = inf for i inrange(k+1): ans = min(dist[n][i], ans) print(ans if ans != inf else -1)
"""解法2: 双向广搜 + 二分答案""" defsolve(t): dist = [inf] * (n + 1) dist[1] = 0 q = deque() q.append(1) while q: u = q.popleft() for v,w in g[u]: w = 0if w <= t else1 if dist[v] > dist[u] + w: dist[v] = dist[u] + w if w == 0: q.appendleft(v) else: q.append(v) return dist[n] <= k
l,r = 0, 1000001 while (l < r): #二分答案 mid = (l+r)//2 if solve(mid): r = mid else: l = mid + 1 print(l if l != 1000001else -1)
inf = float("inf") n,m = map(int, sys.stdin.readline().split()) g = {i:[] for i inrange(1,n+1)} G = {i:[] for i inrange(1,n+1)} ls = [0] ls.extend(list(map(int, sys.stdin.readline().split()))) for _ inrange(m): x,y,z = map(int, sys.stdin.readline().split()) g[x].append(y) G[y].append(x) if z == 2: G[x].append(y) g[y].append(x) dmin, dmax = [101]*(n+1), [0] * (n+1)
defspfa(r, flag): vis = [False]*(n+1) q = Queue() q.put(r) vis[r] = True if flag: dmin[r] = ls[r] else: dmax[r] = ls[r] whilenot q.empty(): x = q.get() vis[x] = False if flag: for v in g[x]: tmp = min(ls[v],dmin[x]) if dmin[v] > tmp: dmin[v] = tmp ifnot vis[v]: q.put(v) vis[v] = True else: for v in G[x]: tmp = max(ls[v], dmax[x]) if dmax[v] < tmp: dmax[v] = tmp ifnot vis[v]: q.put(v) vis[v] = True spfa(1, True) spfa(n, False) ans = -1 for i inrange(1,n+1): if ans < dmax[i] - dmin[i]: ans = dmax[i] - dmin[i] print(ans)
import sys from heapq import * from collections import deque
sys.setrecursionlimit(10005) inf = float("inf") n,r,p,s = map(int,sys.stdin.readline().split()) g = {i:[] for i inrange(n+1)} dist,vis,deg = [inf]*(n+1), [False]*(n+1), [0]*(n+1) color,node,cnt = [0]*(n+1), [[] for _ inrange(n+1)], 0#用于染色统计连通块 for _ inrange(r): a,b,c = map(int,sys.stdin.readline().split()) g[a].append((b,c,0)) g[b].append((a,c,0)) for _ inrange(p): a,b,c = map(int,sys.stdin.readline().split()) g[a].append((b,c,1))
defdfs(x): color[x] = cnt node[cnt].append(x) for y,w,z in g[x]: if z == 1: continue if color[y]: continue dfs(y)
for i inrange(1,n+1): if color[i]: continue cnt += 1 dfs(i)
for x inrange(1,n+1): for y,w,z in g[x]: if z == 1: deg[color[y]] += 1 q = deque() for i inrange(1, cnt+1): if deg[i] == 0: q.append(i) defdijkstra(k): heap = [] for x in node[k]: heappush(heap, (dist[x], x)) while heap: _,x = heappop(heap) if vis[x]: continue vis[x] = True for y,w,z in g[x]: if z == 0: #内层Dijkstra if dist[y] > dist[x] + w: dist[y] = dist[x] + w heappush(heap, (dist[y],y)) continue deg[color[y]] -= 1#外层toposort dist[y] = min(dist[y], dist[x] + w) if deg[color[y]] == 0: q.append(color[y]) dist[s] = 0 while q: k =q.popleft() dijkstra(k)
for i inrange(1,n+1): print(dist[i] if dist[i] != inf else"NO PATH")
"""有向图的最小环问题只需要枚举起点,跑dijkstra dist[i] = 0, 扩展之后, 把起点 i ,dist[i] = inf, 再次从队列中弹出 i 时,可得到从 i 到 i 的最短路,即最小环。 但无向图得把无向边排除 """ import sys from copy import deepcopy
inf = float("inf") n,m = map(int, sys.stdin.readline().split()) g = [[inf]*(n+1) for _ inrange(n+1)] pos = [[0]*(n+1) for _ inrange(n+1)] for _ inrange(m): u,v,w = map(int, sys.stdin.readline().split()) g[u][v] = min(w, g[u][v]) g[v][u] = min(w, g[v][u]) d = deepcopy(g) path = [] defget_path(x, y): #获得从 x 到 z 的路径,pos[x][y] = floyd更新最短路是选取的中间节点的最大编号 if pos[x][y] == 0: return k = pos[x][y] get_path(x, k) #递归一直到 x 的 下一节点为 k 时 path.append(k) get_path(k, y)
ans = inf for k inrange(1,n+1): for i inrange(k): for j inrange(i+1,k): if d[i][j] + g[j][k] + g[k][i] < ans: ans = d[i][j] + g[j][k] + g[k][j] path.clear() path.append(i) get_path(i, j) path.append(j) path.append(k) for i inrange(1,n+1): for j inrange(1,n+1): if d[i][j] > d[i][k] + d[k][j]: d[i][j] = d[i][k] + d[k][j] pos[i][j] = k #记录中转点(1~k-1)
ls = list(".ABCDEFGHIJKLMNOPQRSTUVWXYZ") deffloyd(): for k inrange(1, n+1): for x inrange(1,n+1): for y inrange(1,n+1): g[x][y] |= g[x][k] & g[k][y]
defget_sort(): ans = [] vis = [0] * (n+1) for i inrange(n-1, -1, -1): for x inrange(1, n+1): if vis[x]: continue cnt = 0 for y inrange(1, n+1): if g[x][y]: cnt += 1 if cnt == i: ans.append(ls[x]) vis[x] = 1 break ans = ''.join(ans) + '.' return ans defcheak(): flag = 1 for i inrange(1,n+1): for j inrange(1,n+1): if (g[i][j] == 1and g[j][i] == 1): return2 if (g[i][j] == 0and g[j][i] == 0and j != i): flag = 3 return flag
whileTrue: n,m = map(int, sys.stdin.readline().split()) if n == m and n == 0: break g = [[0]*(n+1) for _ inrange(n+1)] flag, t = 0, m for i inrange(1,m+1): a,b = sys.stdin.readline().strip().split('<') a = ord(a) - ord('A') + 1 b = ord(b) - ord('A') + 1 g[a][b] = 1 floyd() num = cheak() if num == 2: flag = 2 t = min(i,t) elif num == 3: flag = 3 else: flag = 1 t = i break if flag == 3: print("Sorted sequence cannot be determined.") elif flag == 2: print(f'Inconsistency found after {t} relations.') else: print(f'Sorted sequence determined after {t} relations:', end = ' ') print(get_sort()) for i inrange(m-t): s = sys.stdin.readline()
inf = float("inf") n,m = map(int, sys.stdin.readline().split()) g = {i:[] for i inrange(1, n+1)} flow = [0]*(m+1)
for i inrange(1, m+1): u,v,c,f = map(int, sys.stdin.readline().split()) g[u].append((v,c,f)) g[v].append((u,c,f)) flow[i] = f
defdijkstra(x): """带流限制的dijkstra算法""" dist = [inf] * (n + 1) vis = [False] * (n + 1) dist[1] = 0 q = [] heapq.heappush(q, (0, 1)) while q: start = heapq.heappop(q) if vis[start[1]]: continue vis[start[1]] = True for i in g[start[1]]: if i[2] < x: continue if dist[i[0]] > dist[start[1]] + i[1]: dist[i[0]] = dist[start[1]] + i[1] heapq.heappush(q, (dist[i[0]], i[0])) return dist[n] if dist[n] != inf else -1
best_f, best_w = 0, 1 for i inrange(1, m+1): f = flow[i] w = dijkstra(f) if w != -1: if f * best_w > best_f * w: best_f, best_w = f, w print(1000000 * best_f // best_w)
n,m = map(int, sys.stdin.readline().split()) g = {i:[] for i inrange(1,n+1)} edge = [] for _ inrange(m): u,v,w = map(int, sys.stdin.readline().split()) g[u].append((v,w)) edge.append((w,u,v)) ls = [i for i inrange(n+1)] ans = 0 edge.sort() deffind_set(x): #带路径压缩的find_set if x == ls[x]: return x ls[x] = find_set(ls[x]) return ls[x] for i inrange(m): w,u,v = edge[i] x = find_set(u) y = find_set(v) if x != y: ls[y] = x ans += w
inf = float("inf") n,m = map(int, sys.stdin.readline().split()) g = [[inf] * (n+1) for _ inrange(n+1)] for _ inrange(m): x,y,z = map(int, sys.stdin.readline().split()) g[x][y] = z g[y][x] = z vis = [False] * (n+1) mst = [inf] * (n+1) mst[1] = 0 for i inrange(1, n): x = 0 for j inrange(1,n+1): if vis[j]: continue if x == 0or mst[j] < mst[x]: x = j vis[x] = True for y inrange(1, n+1): ifnot vis[y] and mst[y] > g[x][y]: mst[y] = g[x][y] ans = 0 for i inrange(1,n+1): ans += mst[i] print(ans)
defprim(): ans = 0 vis[1] = True for y,w in g[1]: heapq.heappush(q,(w,y)) while q: tmp,x = heapq.heappop(q) if vis[x]: continue vis[x] = True ans += tmp for y,w in g[x]: if vis[y]: continue heapq.heappush(q, (w,y)) print(ans)
n,m = map(int, sys. stdin.readline().split()) g = {i:[] for i inrange(1,n+1)} for _ inrange(m): a,b,c = map(int, sys.stdin.readline().split()) g[a].append((b,c)) g[b].append((a,c)) vis = [False] * (n+1) q = [] prim()
deffind_set(x): if x == ls[x][0]: return x return find_set(ls[x][0])
t = int(sys.stdin.readline()) while t > 0: t -= 1 ans = 0 n = int(sys.stdin.readline()) g = {i: [] for i inrange(1, n + 1)} edge = [] for _ inrange(n - 1): u, v, w = map(int, sys.stdin.readline().split()) g[u].append((v, w)) g[v].append((u, w)) edge.append((w, u, v)) ls = [(i, 1) for i inrange(n + 1)] edge.sort() for i inrange(n - 1): w, u, v = edge[i] x = find_set(u) y = find_set(v) if x != y: j, k = ls[y] l, r = ls[x] ans += (r * k - 1) * (w + 1) ls[x] = (x, k + r) ls[y] = (x, k + r) print(ans)
#初始化 inf = float("inf") vis, c = [False] * 25, [False] * 25# c : color mst = [inf] * 25 s, ans, deg =0, 0, 0# s, 最小生成树的权值, 统计Park的度数 conn = [0]*25#connection 记录每个点连的是哪个点 dic = {"Park":1} #字符串映射为整数 g, tree = [[inf]*25for _ inrange(25)], [[inf]*25for _ inrange(25)] #邻接矩阵, 记录树的路径,MST对应的邻接矩阵 ver, p = [0]*25, 0 f, fx, fy = [0]*25, [0]*25, [0]*25# (fx[i], fy[i]) 是从1 到 i 路径上边权最大的边, 边权为 f[i]
# 输入 n = int(sys.stdin.readline()) cnt = 1 for _ inrange(n): a,b,z = sys.stdin.readline().split() if a != "Park"and a notin dic: cnt += 1 dic[a] = cnt if b != "Park"and b notin dic: cnt += 1 dic[b] = cnt g[dic[a]][dic[b]] = min(int(z), g[dic[a]][dic[b]]) g[dic[b]][dic[a]] = min(int(z), g[dic[b]][dic[a]]) s = int(sys.stdin.readline())
#Prim算法 defprim(root): """对 ver中的 p个点求 mst""" global ans, p, deg mst[root] = 0 for i inrange(1, p+1): x = 0 for j inrange(1, p+1): ifnot vis[ver[j]] and (x == 0or mst[ver[x]] > mst[ver[j]]): x = j vis[ver[x]] = True#找到最小的 mst[ver[x]],加入已选集合 for j inrange(1, p+1): #更新生成树的集合 y = ver[j] ifnot vis[y] and mst[y] > g[ver[x]][y]: mst[y], conn[y] = g[ver[x]][y], ver[x] closest = root for i inrange(1, p+1): if ver[i] == root: continue x = ver[i] ans += mst[x] tree[conn[x]][x] = tree[x][conn[x]] = mst[x] if g[1][closest] > g[1][x]: closest = x deg += 1# 每个连通块与1连一条边 ans += g[1][closest] tree[1][closest] = tree[closest][1] = g[1][closest]
defdfs(x): #找连通块 global p ver[p+1],p = x, p+1 c[x] = True for y inrange(1, cnt+1): if g[x][y] != inf andnot c[y]: dfs(y)
defprim_for_all_comp(): global p for i inrange(2,25): vis[i], mst[i] = False, inf c[1] = True vis[1] = True for i inrange(2,cnt+1): ifnot c[i]: p = 0 dfs(i) # ver中保存了一个连通块里的点 prim(i) #对这个连通块求prim
defdp(x): vis[x] = True for y inrange(2, cnt + 1): if tree[x][y] != inf andnot vis[y]: if f[x] > tree[x][y]: f[y] = f[x] fx[y],fy[y] = fx[x], fy[x] #方案不变 else: f[y] = tree[x][y] fx[y], fy[y] = x, y dp(y)
defsolve(): """用于加边""" global ans min_val, mini = inf, 0 for i inrange(2,cnt+1): #枚举非树边(1,i), 看加哪条边 if tree[1][i] != inf or g[1][i] == inf: continue # 加入非树边(1,i), 删除数边(fx[i], fy[i]) if g[1][i] - tree[fx[i]][fy[i]] < min_val: min_val = g[1][i] - tree[fx[i]][fy[i]] mini = i if min_val >= 0: returnFalse ans += min_val tree[fx[mini]][fy[mini]] = tree[fy[mini]][fx[mini]] = inf tree[1][mini] = tree[mini][1] = g[1][mini] #重新计算以mini[i] 为根的子树的状态 f[mini] = g[1][mini] fx[mini], fy[mini] = 1, mini for i inrange(2,25): vis[i] = False dp(mini) returnTrue
"""主函数""" # 删除1号点,找出每个连通块,各自求Prim prim_for_all_comp() for i inrange(2,25): vis[i] = False dp(1) #树上动规 while deg < s: ifnot solve(): break deg += 1 print(f'Total miles driven: {ans}')
inf = float("inf") n = int(sys.stdin.readline()) g = {i:[] for i inrange(1,n+1)} for _ inrange(n-1): u,v,w = map(int, sys.stdin.readline().split()) g[u].append((v,w))
"""树形DP求树的直径""" d, res = [0]*(n+1), -inf #d[x]表示从点x出发走向以x为根的子树,能够到达最远节点的距离 vis = [False] * (n+1) defdp(x): global res vis[x] = True for y, w in g[x]: if vis[y]: continue dp(y) res = max(ans,d[x] + d[y] + w) # d[x] + d[y] + w = d[yi] + edge[x,yi] + edge[x,yj] + d[yj] j < i d[x] = max(d[x], d[y] + w) # 在枚举到i时d[x]恰好保存了从x到以yj为根的子树最远距离,d[x] = max{d[yj] + edge[e,yj]| j < i}
"""两次BFS求树的直径""" d,pre = [0]*(n+1),[i for i inrange(n+1)] #pre记录了路径 defbfs(r): q = deque() q.append(r) while q: x = q.popleft() for y in g[x]: if d[y]: continue dist[y] = dist[x] + 1 pre[y] = x q.append(y) ans = 1 for i inrange(2,n+1): if d[ans] < d[i]: ans = i return ans
inf = float("inf") n,k = map(int, sys.stdin.readline().split()) g = {i:{} for i inrange(1,n+1)} dist, pre = [0]*(n+1), [i for i inrange(n+1)] q = Queue() for _ inrange(n-1): x,y = map(int, sys.stdin.readline().split()) g[x][y] = g[y][x] = 1
defbfs(r): q.put(r) whilenot q.empty(): x = q.get() for y in g[x]: if dist[y]: continue dist[y] = dist[x] + 1 pre[y] = x q.put(y) ans = 1 for i inrange(2,n+1): if dist[ans] < dist[i]: ans = i return ans
defdp(x): global res vis[x] = True for y in g[x]: if vis[y]: continue dp(y) res = max(res,d[x] + d[y] + g[x][y]) d[x] = max(d[x], d[y] + g[x][y])
p = bfs(1) dist = [0]*(n+1) q = bfs(p) ans = 2*(n-1) - dist[q] + 1 if k == 2: while q != p: g[pre[q]][q] = g[q][pre[q]] = -1 q = pre[q] d, res = [0] * (n + 1), -inf vis = [False] * (n + 1) dp(1) ans = ans - res + 1 print(ans)
n,s = map(int, sys.stdin.readline().split()) g = {i:{} for i inrange(1,n+1)} for _ inrange(n-1): x,y,z = map(int, sys.stdin.readline().split()) g[x][y] = z g[y][x] = z
pre,d = [0]*(n+1), [0]*(n+1) dist,vis = [0]*(n+1),[False]*(n+1) defbfs(r): q = Queue() q.put(r) whilenot q.empty(): x = q.get() for y,w in g[x].items(): if d[y] or y == r: continue d[y] = d[x] + w pre[y] = x q.put(y) ans = r for i inrange(1,n+1): if d[i] > d[ans]: ans = i return ans
defdfs(r): d = 0 for y,w in g[r].items(): if vis[y]: continue vis[y] = True d = max(dfs(y)+w, d) return d
import sys from collections import deque input = sys.stdin.readline
defbfs(r) -> None: """bfs里套了个DP,在nlogn的时间里预处理了基于倍增的向上标记""" d[r] = 1 q = deque() q.append(r) while q: x = q.popleft() for y,w in g[x]: ifnot d[y]: d[y] = d[x] + 1 f[y][0] = x q.append(y) for k inrange(1,20): f[y][k] = f[f[y][k-1]][k-1]
deflca(x,y) -> int: if d[x] < d[y]: x,y = y,x for i inrange(19,-1,-1): if d[f[x][i]] >= d[y]: x = f[x][i] if x == y: return y for i inrange(19,-1,-1): if f[x][i] != f[y][i]: x,y = f[x][i],f[y][i] return f[x][0]
n,m = map(int,input().split()) g = [[] for _ inrange(n+1)] for _ inrange(m): x,y,z = map(int,input().split()) g[x].append((y,z)) g[y].append((x,z))
d = [0]*(n+1) # 点的深度,根为1,0表示还未计算 f = [[0]*20for _ inrange(n+1)] # pow(2,20) > 1000000 bfs(1) # bfs里套了个DP,在 nlogn 的时间里预处理了基于倍增的向上标记
# ----------------------------- # ----------------------------- # @bootstrap deftarjan(x): global cnt # 当前时间戳 cnt += 1 dfn[x] = low[x] = cnt flag = 0# 子树中不满足条件的点的数量 for y in g[x]: ifnot dfn[y]: yield tarjan(y) low[x] = min(low[x], low[y]) # 树边更新low值 if low[y] >= dfn[x]: # 返祖边在x下侧,只要有x就是割点 flag += 1 if (x != root or flag > 1): boo[x] = 1# 如果是root,还要保证儿子数大于1 else: low[x] = min(low[x], dfn[y]) # 非树边更新 low值 yieldNone
n,m = MI() g = [[] for _ inrange(n+1)] for _ inrange(m): x,y = MI() if x == y: continue g[x].append(y) g[y].append(x)
cnt = 0# 用于记录当前时间戳 dfn, boo = [0]*(n+1), [0]*(n+1) # dfn:时间戳, boo:是否为割点 low = [i for i inrange(n+1)] for i inrange(1,n+1): ifnot dfn[i]: root = i tarjan(i) ans = [] for i inrange(1,n+1): if boo[i]: ans.append(i) print1(len(ans)) print_arr(ans)
defadd(x,y,z): global tot tot += 1 ver[tot],edge[tot] = y,z nxt[tot],head[x] = head[x],tot deftarjan(x, in_edge): global cnt # 在solve里面用 nonlocal cnt cnt += 1 dfn[x] = low[x] = cnt i = head[x] while i: y = ver[i] ifnot dfn[y]: tarjan(y,i) low[x] = min(low[x], low[y]) if low[y] > dfn[x]: # (x,y) 为桥 bridge[i] = bridge[i^1] = 1 elif i != (in_edge^1): # 忽略反向边 low[x] = min(low[x],dfn[y]) i = nxt[i] n,m = map(int, input().split()) head = [0]*(n+1) ver,edge,nxt = [0]*(2*m+2),[0]*(2*m+2),[0]*(2*m+2) tot = 1
for i inrange(m): x,y,z = map(int, input().split()) add(x,y,z) add(y,x,z)
bridge = [0]*(2*m+1) dfn,low = [0]*(n+1), [i for i inrange(n+1)] cnt = 0 for i inrange(1,n+1): ifnot dfn[i]:tarjan(i,0) for i inrange(2,tot+1,2): if bridge[i]: print(ver[i^1],ver[i])
# ----------------------------- # ----------------------------- # @bootstrap deftarjan(x): global cnt,tot # 当前时间戳 cnt += 1 dfn[x] = low[x] = cnt st.append(x) if x == root andlen(g[x]) == 0: tot += 1 dcc[tot].append(x) yieldNone flag = 0# 子树中不满足条件的点的数量 for y in g[x]: ifnot dfn[y]: yield tarjan(y) low[x] = min(low[x], low[y]) # 树边更新low值 if low[y] >= dfn[x]: # 返祖边在x下侧,只要有x就是割点 flag,tot= flag + 1, tot + 1 if (x != root or flag > 1): boo[x] = 1# 如果是root,还要保证儿子数大于1 while st[-1] != x: dcc[tot].append(st.pop()) dcc[tot].append(x) else: low[x] = min(low[x], dfn[y]) # 非树边更新 low值 yieldNone
n,m = MI() g = [[] for _ inrange(n+1)] for _ inrange(m): x,y = MI() if x == y: continue g[x].append(y) g[y].append(x)
"""求v-DCC""" cnt,tot = 0,0# 用于记录当前时间戳, dcc编号 dfn, boo = [0]*(n+1), [0]*(n+1) # dfn:时间戳, boo:是否为割点 low = [i for i inrange(n+1)] st,dcc = [],[[] for i inrange(n+1)] # stack, v-DCC for i inrange(1,n+1): ifnot dfn[i]: root = i tarjan(i)
"""v-DCC 缩点""" cnt = tot new_id = [0]*(n+1) for i inrange(1,n+1): if boo[i]: # 给每个割点一个新的编号(从 cnt+1 开始) cnt += 1 new_id[i] = cnt gg = [[] for _ inrange(cnt + 1)] c = [0]*(n+1) # v-DCC 染色 for i inrange(1,tot+1): for j inrange(len(dcc[i])): x = dcc[i][j] if boo[x]: gg[i].append(new_id[x]) gg[new_id[x]].append(i) else: c[x] = i # 除割点外,其他点仅属于1个 v-DCC
deftarjan(x): global cnt,tot # 当前时间戳 cnt += 1 dfn[x] = low[x] = cnt st.append(x) ins[x] = 1 for y in g[x]: ifnot dfn[y]: tarjan(y) low[x] = min(low[x], low[y]) elif ins[y]: low[x] = min(low[x],dfn[y]) if dfn[x] == low[x]: tot += 1 while st[-1] != x: y = st.pop() ins[y] = 0 c[y] = tot, scc[tot].append(y) y = st.pop() ins[y] = 0 c[y] = tot, scc[tot].append(y) cnt,tot = 0,0# 用于记录当前时间戳, scc编号 n,m = map(int, input().split()) g = [[] for _ inrange(n+1)] for _ inrange(m): x,y = map(int, input().split()) if x == y: continue g[x].append(y) g[y].append(x)
"""求SCC""" dfn,c = [0]*(n+1),[0]*(n+1) # dfn:时间戳, c:SCC编号 low = [i for i inrange(n+1)] scc = [[] for _ inrange(n+1)] st,ins = [],[0]*(n+1) # stack, if in stack or not for i inrange(1,n+1): ifnot dfn[i]: tarjan(i)
"""SCC缩点""" gc = [[] for _ inrange(tot+1)] for x inrange(1,n+1): for y in g[x]: if c[x] == c[y]: continue g[c[x]].append(c[y])
inf, _inf = float("inf"), float('-inf') defkm(): defdfs(x): visx[x] = 1 for i inrange(1,H+1): ifnot visy[i] and lx[x] + ly[i] == g[x][i]: #两顶标相加等于边权为有效边 visy[i] = 1 if link[i] == 0or dfs(link[i]): link[i] = x return1 return0 for i inrange(1,P+1): while1: visx,visy = [0]*(P+1), [0]*(H+1) if dfs(i): break d = inf for j inrange(1,P+1): if visx[j]: # 枚举所有左集合访问过的点,找到差值最小的 d for k inrange(1,H+1): ifnot visy[k]: d = min(d, lx[j] + ly[k] - g[j][k]) if d == inf: return0 for j inrange(1,P+1): if visx[j]: lx[j] -= d for j inrange(1,H+1): if visy[j]: ly[j] += d return1
"""P为人的数量,H为房子的数量,人和房子分别为左右集合""" lx,ly,link = [_inf]*(P+1),[0]*(H+1),[0]*(P+1) for i inrange(1,P+1): #初始化顶标 for j inrange(1,H+1): if g[i][j] != 0: lx[i] = max(lx[i], g[i][j]) if km() == 1: ans = 0 for i inrange(1,H+1): ans += g[link[i]][i] # link记录了每个房子(右集合)匹配到的人的下标(左集合) print(-ans) # 题目求的是最小匹配,我们将边取负,求最大匹配,输出相反数
# dinic算法求最大流 # 用法示例 # 创建一个 Maxflow 实例 # mf = Maxflow(100) # n 是节点数 # 添加边,例如: # mf.add_edge(u, v, cap) # 计算最大流 # max_flow = mf.max_flow(source, sink) classMaxflow: # n 节点数, 从0开始编号 def__init__(self, n): self.n = n self.G = [[] for _ inrange(n)] self.depth = [0] * n # cur[u] 表示当前弧下标 self.cur = [0] * n
# 添加一条从 u 到 v 的容量为 cap 的边 defadd_edge(self, u, v, cap): # 正向边 u -> v self.G[u].append([v, cap, len(self.G[v])]) # 分别存(该边的终点,容量,反向边的idx) # 反向边 v -> u,初始容量为 0 self.G[v].append([u, 0, len(self.G[u]) - 1]) # 分别存(该边的终点,容量,正向边的idx)
# 从源点出发进行一次bfs,计算出每个点的深度 # 对当前残差图的BFS构造一个level 图(或为顶点分配深度), 并检查是否更多的流量是可能的。 defbfs(self, s, t): self.depth = [-1] * self.n self.depth[s] = 0 q = deque([s]) while q: u = q.popleft() for v, cap, _ in self.G[u]: if self.depth[v] == -1and cap > 0: self.depth[v] = self.depth[u] + 1 q.append(v) return self.depth[t] != -1
# 从 u 出发,沿着深度优先搜索的路径,不断增广 defdfs(self, u, t, f=inf): if u == t: return f max_flow = 0 while self.cur[u] < len(self.G[u]): v, cap, rev = self.G[u][self.cur[u]] # 只有当 u 的深度加 1 之后等于 v 的深度时,我们才让他流 [不能走回头路] if cap > 0and self.depth[v] == self.depth[u] + 1: # 流多少呢,能装多少流就流多少 df = self.dfs(v, t, min(f - max_flow, cap)) if df > 0: self.G[u][self.cur[u]][1] -= df self.G[v][rev][1] += df max_flow += df if max_flow == f: break # 只有当前面的边都已经流满/不可达,我们才更新 cur[u],下一次直接从第cur[u]条边开始枚举 self.cur[u] += 1 return max_flow