每日一题 2019/4/1

本文介绍了次小生成树的概念及其实现方法,包括严格与非严格次小生成树的区别,通过添加一条边形成环再删除环中最大边的方式求解,并使用倍增算法优化查询过程。

今天学次小生成树,主要是拓展昨天所学。

 

首先,次小生成树分严格与不严格两种,严格就是sum{val2} > sum{val1},不严格就是sum{val2} >= sum{val1}

一个结论:次小生成树一定是MST加一条边,这样一定有环,在这个环中减一条边。

加一条边,加哪条?这个可以枚举

减一条边,减哪条?贪心的思路,分为严格和不严格,减<或者<=加进来的这条边  的所有环上的边中   val最大的那条

加边枚举,很简单,下面考虑一下减边的时候。

令加的这条边的端点为u, v,那么,环的路径就是u  -> lca(u, v) + v -> lca(u, v)

在这个环上一个个找也太蠢了,考虑用倍增优化,用两个数组维护最大值和次大值

Max1[i][j],表示节点i,到它的第2 ^ j个祖先路径上的,最大边权

相应的,Max2[i][j],表示节点i,到它的第2 ^ j个祖先路径上的,次大边权

可以证明,次大边权是一定比加进来的边的边权小的,自己思考。

那么这题就转换成一个普通的倍增LCA + 边跑边维护我们想要的最大边权即可。

其实就是两个倍增,复杂度可以理解为O(mlogm)

代码的实现还是比较困难的,理解了也得一会敲..敲起来真自闭

P4180 【模板】严格次小生成树[BJWC2010]

//My Conquest Is the Sea of Stars.
#pragma GCC diagnostic error "-std=c++11"
#include<set>
#include<map>
#include<cmath>
#include<ctime>
#include<queue>
#include<stack>
#include<cstdio>
#include<string>
#include<vector>
#include<cstdlib>
#include<cstring>
#include<iomanip>
#include<ext/rope>
#include<iostream>
#include<algorithm>
#define endl "\n"
#define fi first
#define se second
#define gcd __gcd
#define pb push_back
#define mp make_pair
#define lowbit(x) x & (-x)
#define PII  pair<int, int> 
#define all(x) x.begin(), x.end()
#define rep(i, a, b) for(__typeof(b) i = a; i <= (b); i++)
#define Rep(i, a, b) for(__typeof(a) i = a; i >= (b); i--)
#define FAST ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
typedef long long ll;
typedef unsigned long long ull;
const int inf = 0x3f3f3f3f;
const int mod = (int)1e9 + 7;
const int maxn = (int)3e5 + 5;
const ll INF = 0x3f3f3f3f3f3f3f3f;
using namespace std;
using __gnu_cxx::crope;

#define int ll

struct edge{
	int from, to, val;
	friend bool operator <(edge a, edge b){
		return a.val < b.val;
	}
}es[maxn];

vector<int> G[maxn];
bool vis[maxn];
int fa[maxn], dep[maxn], acst[maxn][22];
int Max1[maxn][22], Max2[maxn][22];
int lg[maxn];
int n, m; 

int Find(int x) { return fa[x] == x ? x : fa[x] = Find(fa[x]); }
void uni(int x, int y) { fa[Find(x)] = Find(y); }

void init() {
	//memset(dep, 0, sizeof(dep));
	//memset(acst, 0, sizeof(acst));
	//memset(Max1, 0, sizeof(Max1));
	//memset(Max2, 0, sizeof(Max2));
	//rep(i, 0, n) vis[i] = 0;
	rep(i, 0, n) fa[i] = i; 
	//rep(i, 0, n) G[i].clear();
	rep(i, 1, n){
		lg[i] = lg[i-1] + ((1 << lg[i-1]) == i);
	}
}

void dfs(int x){
	int len = G[x].size();
	rep(i, 0, len - 1){
		int y = G[x][i];
		int nxt = es[y].from == x ? es[y].to : es[y].from;
		int val = es[y].val;
		if(acst[x][0] == nxt) continue;
		acst[nxt][0] = x, Max1[nxt][0] = val;
		dep[nxt] = dep[x] + 1;
		dfs(nxt);
	}
}

void work(){
	rep(j, 1, 19){
		rep(i, 1, n){
			acst[i][j] = acst[acst[i][j-1]][j-1];
			Max1[i][j] = max(Max1[i][j-1], Max1[acst[i][j-1]][j-1]);
			Max2[i][j] = max(Max2[i][j-1], Max2[acst[i][j-1]][j-1]);
			if(Max1[i][j-1] != Max1[acst[i][j-1]][j-1]) Max2[i][j] = max(Max2[i][j], min(Max1[i][j-1], Max1[acst[i][j-1]][j-1]));
		}
	}
}

int MAX(int x, int a, int b, int val)
{
	if(val > Max1[a][b]) return max(x, Max1[a][b]);
	return max(x, Max2[a][b]);
}

int Get(int x, int y, int val){
	if(dep[x] < dep[y]) swap(x, y);
	int i, res = 0;
	while(dep[x] > dep[y]) {
		i = lg[dep[x]-dep[y]] - 1;
		res = MAX(res, x, i, val);
		x = acst[x][i];
	}
	if(x == y) return res;
	i = 0;
	while(acst[x][i] != acst[y][i]) i++;
	for( ; i >= 0; i--){
		if(acst[x][i] != acst[y][i]) {
			res = MAX(MAX(res, x, i, val), y, i, val);
			x = acst[x][i], y = acst[y][i];
		}
	}
	return MAX(MAX(res, x, 0, val), y, 0, val); 
}

int32_t main()
{
	scanf("%lld %lld", &n, &m);
	init();
	rep(i, 1, m){
		scanf("%lld %lld %lld", &es[i].from, &es[i].to, &es[i].val);
	}
	sort(es + 1, es + m + 1);
	int res = 0, cnt = 0;
	rep(i, 1, m){
		if(cnt >= n) break;
		int fu = Find(es[i].from), fv = Find(es[i].to);
		if(fu != fv){
			vis[i] = 1;
			uni(fu, fv);
			res += es[i].val;
			cnt++;
			G[es[i].from].pb(i);
			G[es[i].to].pb(i);
		}
	}
	dep[1] = 1;
	dfs(1);
	work();
	int ans = INF, t;
	rep(i, 1, m){
		if(!vis[i]){
			t = Get(es[i].from, es[i].to, es[i].val);
			ans = min(ans, res + es[i].val - t);
		}
	}
	printf("%lld\n", ans);
	return 0;
}

 

【顶级EI完整复现】【DRCC】考虑N-1准则的分布鲁棒机会约束低碳经济调度(Matlab代码实现)内容概要:本文介绍了名为《【顶级EI完整复现】【DRCC】考虑N-1准则的分布鲁棒机会约束低碳经济调度(Matlab代码实现)》的技术资源,聚焦于电力系统中低碳经济调度问题,结合N-1安全准则与分布鲁棒机会约束(DRCC)方法,提升调度模型在不确定性环境下的鲁棒性和可行性。该资源提供了完整的Matlab代码实现,涵盖建模、优化求解及仿真分析全过程,适用于复杂电力系统调度场景的科研复现与算法验证。文中还列举了大量相关领域的研究主题与代码资源,涉及智能优化算法、机器学习、电力系统管理、路径规划等多个方向,展示了广泛的科研应用支持能力。; 适合人群:具备一定电力系统、优化理论和Matlab编程基础的研究生、科研人员及从事能源调度、智能电网相关工作的工程师。; 使用场景及目标:①复现高水平期刊(如EI/SCI)关于低碳经济调度的研究成果;②深入理解N-1安全约束与分布鲁棒优化在电力调度中的建模方法;③开展含新能源接入的电力系统不确定性优化研究;④为科研项目、论文撰写或工程应用提供可运行的算法原型和技术支撑。; 阅读建议:建议读者结合文档提供的网盘资源,下载完整代码与案例数据,按照目录顺序逐步学习,并重点理解DRCC建模思想与Matlab/YALMIP/CPLEX等工具的集成使用方式,同时可参考文中列出的同类研究方向拓展研究思路。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值