关于最小生成树
前言:
由于太懒了 所以做完之后一直没弄
现在还是懒得弄...
把代码粘过来 题目的话 下次吧...(也可能就没有下次了)
1. 黑暗城堡
/*
Time: 12.30
Worker: Blank_space
Source: #10064. 「一本通 3.1 例 1」黑暗城堡
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define int long long
#define void inline void
#define ull unsigned long long
#define Orz cout<<"ZXS AK IOI"<<'\n'
#define emm(x) memset(x,0,sizeof x)
#define emmm(x) memset(x,0x3f,sizeof x)
using namespace std;
/*--------------------------------------头文件*/
const int A = 1e4 + 7;
const int B = 1e5 + 7;
const int C = 1e6 + 7;
const int D = 1e7 + 7;
const int mod = 2147483647;
const int INF = 0x3f3f3f3f;
/*------------------------------------常量定义*/
int n, m, dis[1010], maxdep, ans = 1, sum[1010];
bool vis[1010];
struct edge {
int v, w, nxt;
}e[C << 1];
int head[1010], js;
struct node {
int u, d;
bool operator < (const node & x) const
{
return d < x.d;
}
};
/*------------------------------------变量定义*/
inline int read() {
int x = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
return x * f;
}
/*----------------------------------------快读*/
void add_edge(int u, int v, int w)
{
e[++js].v = v;
e[js].w = w;
e[js].nxt = head[u];
head[u] = js;
}
void scan()
{
n = read(); m = read();
for(int i = 1; i <= m; i++)
{
int x = read(), y = read(), z = read();
add_edge(x, y, z); add_edge(y, x, z);
}
}
void dijk(int s)
{
queue <node> q;
q.push((node){s, 0});
emmm(dis); dis[s] = 0;
while(!q.empty())
{
node t = q.front(); q.pop();
int u = t.u;
for(int i = head[u]; i; i = e[i].nxt)
{
int v = e[i].v, w = e[i].w;
if(dis[v] > dis[u] + w)
{
dis[v] = dis[u] + w;
q.push((node){v, dis[v]});
}
}
}
}
void add()
{
for(int u = 1; u <= n; u++)
for(int i = head[u]; i; i = e[i].nxt)
if(dis[e[i].v] == dis[u] + e[i].w) sum[e[i].v]++;
}
void print()
{
for(int i = 1; i <= n; i++)
if(sum[i]) ans = ans * sum[i] % mod;
printf("%lld", ans);
}
/*----------------------------------------函数*/
signed main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
scan();
dijk(1);
add();
print();
// fclose(stdin);
// fclose(stdout);
return 0;
}
2. 北极通讯网络
不会(简洁 明了)
3. 新的开始
/*
Time: 1.2
Worker: Blank_space
Source: #10066. 「一本通 3.1 练习 1」新的开始
*/
/*--------------------------------------------*/
#include<cstdio>
#include<algorithm>
using namespace std;
/*--------------------------------------头文件*/
const int A = 1e4 + 7;
const int B = 1e5 + 7;
const int C = 1e6 + 7;
const int D = 1e7 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const int FFF = 0x8fffffff;
/*------------------------------------常量定义*/
int n, a[310], fa[310], ans, cnt;
struct edge {
int u, v, w, nxt;
bool operator < (const edge & x) const {return w < x.w;}
}e[C];
/*------------------------------------变量定义*/
inline int read() {
int x = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
return x * f;
}
/*----------------------------------------快读*/
int find(int x) {return x == fa[x] ? x : fa[x] = find(fa[x]);}
/*----------------------------------------函数*/
int main()
{
n = read();
for(int i = 1; i <= n; i++) a[i] = read(), fa[i] = i;
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= n; j++)
{
int x = read();
if(i == j) continue;
e[++cnt].u = i; e[cnt].v = j; e[cnt].w = x;
}
e[++cnt].u = i; e[cnt].v = n + 1; e[cnt].w = a[i];
e[++cnt].u = n + 1; e[cnt].v = i; e[cnt].w = a[i];
}
fa[n + 1] = n + 1; sort(e + 1, e + 1 + cnt);
for(int i = 1; i <= cnt; i++)
{
int u = e[i].u, v = e[i].v, w = e[i].w;
int x = find(u), y = find(v);
if(x == y) continue;
fa[y] = x; ans += w;
}
printf("%d", ans);
return 0;
}
4. 构造完全图
/*
Time: 1.2
Worker: Blank_space
Source: #10067. 「一本通 3.1 练习 2」构造完全图
*/
/*--------------------------------------------*/
#include<cstdio>
#include<algorithm>
#define int long long
using namespace std;
/*--------------------------------------头文件*/
const int A = 1e4 + 7;
const int B = 1e5 + 7;
const int C = 1e6 + 7;
const int D = 1e7 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const int FFF = 0x8fffffff;
/*------------------------------------常量定义*/
int n, fa[B], cnt, num[B], ans;
struct edge {
bool operator < (const edge & x) const {return w < x.w;}
int u, v, w;
}e[B << 1];
/*------------------------------------变量定义*/
inline int read() {
int x = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
return x * f;
}
/*----------------------------------------快读*/
int find(int x) {return x == fa[x] ? x : fa[x] = find(fa[x]);}
/*----------------------------------------函数*/
signed main()
{
n = read();
for(int i = 1; i < n; i++)
{
int x = read(), y = read(), z = read();
e[++cnt].u = x; e[cnt].v = y; e[cnt].w = z;
e[++cnt].u = y; e[cnt].v = x; e[cnt].w = z;
fa[i] = i; num[i] = 1;
}
fa[n] = n; num[n] = 1;
sort(e + 1, e + 1 + cnt);
for(int i = 1; i <= cnt; i++)
{
int u = e[i].u, v = e[i].v, w = e[i].w;
int x = find(u), y = find(v);
if(x == y) continue;
ans += (num[x] * num[y] - 1) * (w + 1) + w;
fa[y] = x; num[x] += num[y];
}
printf("%lld", ans);
return 0;
}
5. 秘密的牛奶运输
/*
Time: 1.2
Worker: Blank_space
Source: #10068. 「一本通 3.1 练习 3」秘密的牛奶运输
严格次小生成树
先把最小生成树跑出来 再枚举每一条非树边 找链接这两点的路径上的最大边进行替换
*/
/*--------------------------------------------*/
#include<cstdio>
#include<algorithm>
#define int long long
using namespace std;
/*--------------------------------------头文件*/
const int A = 1e4 + 7;
const int B = 1e5 + 7;
const int C = 1e6 + 7;
const int D = 1e7 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const int FFF = 0x8fffffff;
/*------------------------------------常量定义*/
int n, m, _ans = 1e10, d[510], dfn[510], pos[510], top[510], dep[510], siz[510], son[510], fa[510], cnt, sum, f[510];
struct edge {
int u, v, w, nxt;
bool t;
bool operator < (const edge & x) const {return w < x.w;}
}e[B], a[B];
int head[510], js;
/*------------------------------------变量定义*/
inline int read() {
int x = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
return x * f;
}
/*----------------------------------------快读*/
int find(int x) {return x == f[x] ? x : f[x] = find(f[x]);}
void add_edge(int u, int v, int w)
{
e[++js].u = u;
e[js].v = v;
e[js].w = w;
e[js].nxt = head[u];
head[u] = js;
}
namespace seg {
#define ls(x) x << 1
#define rs(x) x << 1 | 1
struct node {
int l, r, mid, maxx, cmax;
}t[B << 2];
void push_up(int p)
{
t[p].maxx = max(t[ls(p)].maxx, t[rs(p)].maxx);
t[p].cmax = max(t[p].maxx == t[ls(p)].maxx ? t[ls(p)].cmax : t[ls(p)].maxx, t[p].maxx == t[rs(p)].maxx ? t[rs(p)].cmax : t[rs(p)].maxx);
}
void build(int p, int l, int r)
{
t[p].l = l; t[p].r = r; t[p].mid = (l + r) >> 1;
if(l == r) {t[p].maxx = d[pos[l]]; t[p].cmax = -1; return ;}
build(ls(p), l, t[p].mid); build(rs(p), t[p].mid + 1, r);
push_up(p);
}
node query(int p, int l, int r)
{
if(l <= t[p].l && t[p].r <= r) return t[p];
node res1, res2, res3;
res1.maxx = res1.cmax = res2.maxx = res2.cmax = res3.maxx = res3.cmax = 0;
if(l <= t[p].mid) res1 = query(ls(p), l, r);
if(r > t[p].mid) res2 = query(rs(p), l, r);
res3.maxx = max(res1.maxx, res2.maxx);
res3.cmax = max(res3.maxx == res1.maxx ? res1.cmax : res1.maxx, res3.maxx == res2.maxx ? res2.cmax : res2.maxx);
return res3;
}
}
namespace cut {
void dfs(int u, int pre)
{
fa[u] = pre; dep[u] = dep[pre] + 1; siz[u] = 1;
for(int i = head[u]; i; i = e[i].nxt)
{
int v = e[i].v, w = e[i].w;
if(v == pre) continue; d[v] = w;
dfs(v, u); siz[u] += siz[v];
if(!son[u] || siz[son[u]] < siz[v]) son[u] = v;
}
}
void dfs2(int u, int tp)
{
dfn[u] = ++cnt; pos[cnt] = u; top[u] = tp;
if(!son[u]) return ; dfs2(son[u], tp);
for(int i = head[u]; i; i = e[i].nxt)
{
int v = e[i].v;
if(v == fa[u] || v == son[u]) continue;
dfs2(v, v);
}
}
int query(int x, int y, int z)
{
int ans = 0;
while(top[x] != top[y])
{
if(dep[top[x]] < dep[top[y]]) swap(x, y);
seg::node res = seg::query(1, dfn[top[x]], dfn[x]);
ans = max(ans, res.maxx == z ? res.cmax : res.maxx);
x = fa[top[x]];
}
if(x == y) return ans;
if(dfn[x] > dfn[y]) swap(x, y);
seg::node res = seg::query(1, dfn[x] + 1, dfn[y]);
ans = max(ans, res.maxx == z ? res.cmax : res.maxx);
return ans;
}
}
/*----------------------------------------函数*/
signed main()
{
n = read(); m = read();
for(int i = 1; i <= n; i++) f[i] = i;
for(int i = 1; i <= m; i++) a[i].u = read(), a[i].v = read(), a[i].w = read();
sort(a + 1, a + 1 + m);
for(int i = 1; i <= m; i++)
{
int u = a[i].u, v = a[i].v, w = a[i].w;
int x = find(u), y = find(v);
if(x == y) continue; a[i].t = 1; sum += w;
f[y] = x; add_edge(u, v, w); add_edge(v, u, w);
}
cut::dfs(1, 0); cut::dfs2(1, 1); seg::build(1, 1, cnt);
for(int i = 1; i <= m; i++)
{
if(a[i].t) continue;
int u = a[i].u, v = a[i].v, w = a[i].w;
int res = cut::query(u, v, w);
_ans = min(_ans, w - res);
}
printf("%lld", _ans + sum);
return 0;
}
6. Tree
/*
Time: 1.2
Worker: Blank_space
Source: #10069. 「一本通 3.1 练习 4」Tree
黑白边分开选 白边优先
然而并不对
二分加权最小生成树 二分一个权值 加到白边上 排序 跑最小生成树
仍旧过不了 二分挂掉了
一段时间的修码...
二分并没有问题 挂掉的是排序
当权值相等时按照白点在前的顺序排 AC
*/
/*--------------------------------------------*/
#include<cstdio>
#include<algorithm>
using namespace std;
/*--------------------------------------头文件*/
const int A = 1e4 + 7;
const int B = 1e5 + 7;
const int C = 1e6 + 7;
const int D = 1e7 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const int FFF = 0x8fffffff;
/*------------------------------------常量定义*/
int n, m, ned, cnt, fa[B], ans, sum, maxx, _ans;
struct edge {
int u, v, w, nxt;
bool p;
bool operator < (const edge & x) const {return w == x.w ? p > x.p : w < x.w;}
}e[B << 1];
/*------------------------------------变量定义*/
inline int read() {
int x = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
return x * f;
}
/*----------------------------------------快读*/
int find(int x) {return x == fa[x] ? x : fa[x] = find(fa[x]);}
int kruskal()
{
int sum = 0; ans = 0;
sort(e + 1, e + 1 + m);
for(int i = 1; i <= n; i++) fa[i] = i;
for(int i = 1; i <= m; i++)
{
int u = e[i].u, v = e[i].v, w = e[i].w;
int x = find(u), y = find(v);
if(x == y) continue; ans += w;
fa[y] = x; if(e[i].p) sum++;
}
return sum;
}
bool check(int x)
{
for(int i = 1; i <= m; i++) if(e[i].p) e[i].w += x;
int num = kruskal();
for(int i = 1; i <= m; i++) if(e[i].p) e[i].w -= x;
return num >= ned;
}
/*----------------------------------------函数*/
int main()
{
// freopen("tree20.in", "r", stdin);
n = read(); m = read(); ned = read();
for(int i = 1; i <= m; i++)
{
int x = read() + 1, y = read() + 1, z = read(), o = read();
e[i].u = x; e[i].v = y; e[i].w = z; e[i].p = o ^ 1;
}
int l = -105, r = 105;
while(l <= r)
{
int mid = (l + r) >> 1;
if(check(mid)) _ans = mid, l = mid + 1;
else r = mid - 1;
}
check(_ans);
ans -= ned * _ans;
printf("%d", ans);
return 0;
}
7. 最小生成树计数
/*
Time: 1.2
Worker: Blank_space
Source: #10070. 「一本通 3.1 练习 5」最小生成树计数
不同的树一定是以权值相等的非树边替换了树边 直接递归找相等的边
发现不太好实现 且最终答案难以统计
参照题解
每种权值的边使用数量确定 深搜判断
*/
/*--------------------------------------------*/
#include<cstdio>
#include<algorithm>
using namespace std;
/*--------------------------------------头文件*/
const int A = 1e4 + 7;
const int B = 1e5 + 7;
const int C = 1e6 + 7;
const int D = 1e7 + 7;
const int mod = 31011;
const int INF = 0x3f3f3f3f;
const int FFF = 0x8fffffff;
/*------------------------------------常量定义*/
int n, m, sum, ans = 1, fa[110], cnt, tot;
struct edge {
int u, v, w, nxt;
bool p;
bool operator < (const edge & x) const {return w < x.w;}
}e[A], c[A];
int head[110], js;
/*------------------------------------变量定义*/
inline int read() {
int x = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
return x * f;
}
/*----------------------------------------快读*/
int find(int x) {return x == fa[x] ? x : find(fa[x]);}
void dfs(int t, int i, int num)
{
if(i == c[t].v + 1) {if(num == c[t].w) sum++; return ;}
int u = e[i].u, v = e[i].v;
int x = find(u), y = find(v);
if(x != y) {fa[y] = x; dfs(t, i + 1, num + 1); fa[x] = x; fa[y] = y;}
dfs(t, i + 1, num);
}
/*----------------------------------------函数*/
int main()
{
n = read(); m = read();
for(int i = 1; i <= n; i++) fa[i] = i;
for(int i = 1; i <= m; i++)
e[i].u = read(), e[i].v = read(), e[i].w = read();
sort(e + 1, e + 1 + m);
for(int i = 1; i <= m; i++)
{
int u = e[i].u, v = e[i].v, w = e[i].w;
if(w != e[i - 1].w) {c[cnt].v = i - 1; c[++cnt].u = i;}
int x = find(u), y = find(v);
if(x == y) continue;
fa[y] = x; c[cnt].w++; tot++;
}
c[cnt].v = m; if(tot != n - 1) {puts("0"); return 0;}
for(int i = 1; i <= n; i++) fa[i] = i;
for(int i = 1; i <= cnt; i++)
{
sum = 0;
dfs(i, c[i].u, 0);
ans = ans * sum % mod;
for(int j = c[i].u; j <= c[i].v; j++)
{
int x = find(e[j].u), y = find(e[j].v);
if(x == y) continue; fa[y] = x;
}
}
printf("%d", ans);
return 0;
}
8. 次小生成树
/*
Time: 12.30
Worker: Blank_space
Source: P4180 严格次小生成树
先跑出最小生成树 枚举非树边 考虑加边删边
维护最大值与严格次大值 计算加边
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define ll long long
#define void inline void
#define ull unsigned long long
#define Orz cout<<"ZXS AK IOI"<<'\n'
#define emm(x) memset(x,0,sizeof x)
#define emmm(x) memset(x,0x3f,sizeof x)
using namespace std;
/*--------------------------------------头文件*/
const int A = 1e4 + 7;
const int B = 1e5 + 7;
const int C = 1e6 + 7;
const int D = 1e7 + 7;
const int mod = 1e9 + 7;
const int INF = 1e16 + 7;
/*------------------------------------常量定义*/
inline int read() {
int x = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
return x * f;
}
/*----------------------------------------快读*/
int n, m, fa[C], dep[C], top[C], siz[C], son[C], cnt, dfn[C], pos[C], f[C], _a[C], tot;
ll _ans;
struct edge {
int u, v, nxt;
ll w;
// bool operator < (const edge & x)const{return w == x.w ? u == x.u ? v < x.v : u < x.u : w < x.w;}
}e[C << 1];
int head[C], js;
struct dg {
int x, y;
ll z;
bool p;
bool operator < (const dg & t) const {return z < t.z;}
}a[C];
/*------------------------------------变量定义*/
int find(int x) {return x == f[x] ? x : f[x] = find(f[x]);}
//bool cmp(edge x, edge y) {return x.w < y.w;}
void add_edge(int u, int v, ll w)
{
e[++js].u = u;
e[js].v = v;
e[js].w = w;
e[js].nxt = head[u];
head[u] = js;
}
namespace seg {
#define ls(x) x << 1
#define rs(x) x << 1 | 1
struct node {
int l, r, mid;
ll max, cax;
}t[B << 2];
void push_up(int p)
{
t[p].max = max(t[ls(p)].max, t[rs(p)].max);
t[p].cax = max(t[p].max == t[ls(p)].max ? t[ls(p)].cax : t[ls(p)].max, t[p].max == t[rs(p)].max ? t[rs(p)].cax : t[rs(p)].max);
}
void build(int p, int l, int r)
{
t[p].l = l; t[p].r = r; t[p].mid = (l + r) >> 1;
if(l == r) {t[p].max = _a[pos[l]]; t[p].cax = -1; return ;}
build(ls(p), l, t[p].mid); build(rs(p), t[p].mid + 1, r);
push_up(p);
}
node query(int p, int l, int r)
{
if(l <= t[p].l && t[p].r <= r) return t[p];
node res1, res2, res3;
res1.max = res1.cax = res2.max = res2.cax = res3.max = res3.cax = 0;
if(l <= t[p].mid) res1 = query(ls(p), l, r);
if(r > t[p].mid) res2 = query(rs(p), l, r);
res3.max = max(res1.max, res2.max);
res3.cax = max(res3.max == res1.max ? res1.cax : res1.max, res3.max == res2.max ? res2.cax : res2.max);
return res3;
}
}
namespace cut {
void dfs(int u, int pre)
{
fa[u] = pre; dep[u] = dep[pre] + 1; siz[u] = 1;
for(int i = head[u]; i; i = e[i].nxt)
{
int v = e[i].v, w = e[i].w;
if(v == pre) continue; _a[v] = w;
dfs(v, u); siz[u] += siz[v];
if(!son[u] || siz[son[u]] < siz[v]) son[u] = v;
}
}
void dfs2(int u, int tp)
{
dfn[u] = ++cnt; pos[cnt] = u; top[u] = tp;
if(!son[u]) return ; dfs2(son[u], tp);
for(int i = head[u]; i; i = e[i].nxt)
{
int v = e[i].v;
if(v == fa[u] || v == son[u]) continue;
dfs2(v, v);
}
}
int query(int x, int y, int z)
{
ll ans = 0;
while(top[x] != top[y])
{
if(dep[top[x]] < dep[top[y]]) swap(x, y);
seg::node res = seg::query(1, dfn[top[x]], dfn[x]);
ans = max(ans, res.max == z ? res.cax : res.max);
x = fa[top[x]];
}
if(x == y) return ans;
if(dfn[x] > dfn[y]) swap(x, y);
seg::node res = seg::query(1, dfn[x] + 1, dfn[y]);
ans = max(ans, res.max == z ? res.cax : res.max);
return ans;
}
}
/*----------------------------------------函数*/
signed main()
{
// freopen("ex_tree1.in","r",stdin);
// freopen(".out","w",stdout);
freopen("milktrans2.in", "r", stdin);
n = read(); m = read();
for(int i = 1; i <= n; i++) f[i] = i;
for(int i = 1; i <= m; i++) a[i].x = read(), a[i].y = read(), a[i].z = read();
sort(a + 1, a + 1 + m);
for(int i = 1; i <= m; i++)
{
int u = a[i].x, v = a[i].y;
ll w = a[i].z;
int x = find(u), y = find(v);
if(x == y) continue;
f[y] = x; a[i].p = 1; _ans += w;
add_edge(u, v, w); add_edge(v, u, w);
}
cut::dfs(1, 0); cut::dfs2(1, 1); seg::build(1, 1, n);
ll ans = INF;
for(int i = 1; i <= m; i++)
{
if(a[i].p) continue;
int u = a[i].x, v = a[i].y;
ll w = a[i].z;
ll res = cut::query(u, v, w);
ans = min(ans, w - res);
}
printf("%lld", ans + _ans);
// fclose(stdin);
// fclose(stdout);
return 0;
}