【Luogu】 P4649 [IOI2007] training 训练路径

题目链接

点击打开链接

题目解法

好神仙的题啊!!!

首先一个合法的选路径方案等价于没有偶环出现

我们先判掉和树边能组成偶环的非树边

然后考虑一个结论是:如果有一条边被两个偶环都经过了一次,那么这个方案不合法

为什么?考虑把这两条路径的交去掉这两条路径的并,剩下的是一个偶环

考虑把删边变为加边,需要加上权值和最大的边使得方案合法

可以发现每个点的度数很小,于是考虑状压

令 f u , S f_{u,S} fu,S 为在 u u u 的子树中, u u u 的儿子集合 S S S 不考虑在内的方案数

这样只需要枚举每一条 l c a ( x , y ) = u lca(x,y)=u lca(x,y)=u 的非树边,然后转移即可

时间复杂度 O ( 2 10 m ) O(2^{10}m) O(210m)

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N=1100,M=5100;
int n,m,dp[N][1<<10],depth[N],fa[N];
int e[N<<1],ne[N<<1],h[N],idx;
int id[N][N],rv[N][20];
struct Node{ int x,y,z;}E[M];
vector<Node> qry[N];
inline int read(){
	int FF=0,RR=1;
	char ch=getchar();
	for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
	for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
	return FF*RR;
}
void add(int x,int y){ e[idx]=y,ne[idx]=h[x],h[x]=idx++;}
void dfs(int u){
	depth[u]=depth[fa[u]]+1;
	for(int i=h[u];~i;i=ne[i]) if(e[i]!=fa[u]) fa[e[i]]=u,dfs(e[i]);
}
int get_lca(int x,int y){
	if(depth[x]>depth[y]) swap(x,y);
	while(depth[y]>depth[x]) y=fa[y];
	while(x!=y) x=fa[x],y=fa[y];
	return x;
}
void dfs2(int u){
	int cnt=0;
	for(int i=h[u];~i;i=ne[i]) if(e[i]!=fa[u]){
		id[u][e[i]]=1<<cnt,rv[u][cnt]=e[i],cnt++;
		dfs2(e[i]);
	}
	for(int S=0;S<1<<cnt;S++)
		for(int i=0;i<cnt;i++) if(!(S>>i&1)) dp[u][S]+=dp[rv[u][i]][0];
	for(Node t:qry[u]){
		int x=t.x,y=t.y,res=t.z,exc=0;
		if(x!=u){
            res+=dp[x][0];
			while(fa[x]!=u) res+=dp[fa[x]][id[fa[x]][x]],x=fa[x];
			exc|=id[fa[x]][x];
		}
		if(y!=u){
            res+=dp[y][0];
			while(fa[y]!=u) res+=dp[fa[y]][id[fa[y]][y]],y=fa[y];
			exc|=id[fa[y]][y];
		}
		for(int S=0;S<1<<cnt;S++) if((S|exc)==S+exc) dp[u][S]=max(dp[u][S],dp[u][S+exc]+res);
	}
}
int main(){
	n=read(),m=read();
	memset(h,-1,sizeof(h));
    int cnt=0;
	for(int i=1;i<=m;i++){
		int x=read(),y=read(),z=read();
		if(!z) add(x,y),add(y,x);
		else E[++cnt]={x,y,z};
	}
	dfs(1);
	int tot=0;
	for(int i=1;i<=cnt;i++){
		int lca=get_lca(E[i].x,E[i].y);tot+=E[i].z;
        if(~(depth[E[i].x]+depth[E[i].y]-2*depth[lca])&1) qry[lca].push_back(E[i]);
	}
	dfs2(1);
	printf("%d\n",tot-dp[1][0]);
	fprintf(stderr,"%d ms\n",int(1e3*clock()/CLOCKS_PER_SEC));
	return 0;
}
相关推荐
野渡拾光1 小时前
【考研408数据结构-05】 串与KMP算法:模式匹配的艺术
数据结构·考研·算法
tainshuai3 小时前
用 KNN 算法解锁分类的奥秘:从电影类型到鸢尾花开
算法·分类·数据挖掘
Coovally AI模型快速验证9 小时前
农田扫描提速37%!基于检测置信度的无人机“智能抽查”路径规划,Coovally一键加速模型落地
深度学习·算法·yolo·计算机视觉·transformer·无人机
pusue_the_sun9 小时前
数据结构:二叉树oj练习
c语言·数据结构·算法·二叉树
RaymondZhao3410 小时前
【全面推导】策略梯度算法:公式、偏差方差与进化
人工智能·深度学习·算法·机器学习·chatgpt
zhangfeng113310 小时前
DBSCAN算法详解和参数优化,基于密度的空间聚类算法,特别擅长处理不规则形状的聚类和噪声数据
算法·机器学习·聚类
啊阿狸不会拉杆11 小时前
《算法导论》第 32 章 - 字符串匹配
开发语言·c++·算法
小学生的信奥之路11 小时前
洛谷P3817题解:贪心算法解决糖果分配问题
c++·算法·贪心算法
你知道网上冲浪吗12 小时前
【原创理论】Stochastic Coupled Dyadic System (SCDS):一个用于两性关系动力学建模的随机耦合系统框架
python·算法·数学建模·数值分析
地平线开发者13 小时前
征程 6 | PTQ 精度调优辅助代码,总有你用得上的
算法·自动驾驶