洛谷P1453 城市环路
这道题的解题关键在于:n个点,n条边
说起n个点,n-1条边,联通,必然是树形结构
那再多一条边呢?
这种图有自己的名字:基环树,也就是只有一个环的树
比如:
在做这题前可以先去看看:洛谷P1352没有上司的舞会
要求一条边的两个端点不能同时取,处理方法是设dp[i][0/1]表示这点取或者不取
转移方程为:
dp[u][0]+=max(dp[to][0],dp[to][1]); dp[u][1]+=dp[to][0];
其中该点不选(0)时,对son没有影响,贪心地选择最大值即可;
该点要选(1)时,要求son一定不能选,就只能+dp[son][0];
这道题可以看成是基环树版本的P1352
做法是分别找环上两点S和T,以这两点为根进行一次dfs,最后取dp[S][0]和dp[T][0]的最大值
因为状态转移方程可以保证树的两边点不能同时选,但无法保证S和T有没有同时选,这个dp过程是不知道的
假设最优解为选S,不选T,那么答案在dp[T][0],同理dp[S][0]
如果最优解是S和T都不选,那更好了>_<
PS:对于基环树,一般可以删去一条边,转化为比较熟悉的树,或者像这题这样什么的
#include<bits/stdc++.h> using namespace std; const int maxn=int(1e5)+7; int vis[maxn],vis2[maxn],n,p[maxn],head[maxn],cnt=0,s,t,isfind=0; long long ans=0,dp[maxn][3],dp2[maxn][3]; double k; struct lys{ int from,to,nxt; }e[maxn*3]; void add(int from,int to) { cnt++;e[cnt].from=from;e[cnt].to=to;e[cnt].nxt=head[from];head[from]=cnt; } void build(int fa,int u) { vis[u]=1; for(int i=head[u];i;i=e[i].nxt) { int to=e[i].to; if(to==fa) continue; if(vis[to]==1) { s=to;t=u;continue; } build(u,to); } } void dfs(int fa,int u) { vis[u]=1; dp[u][0]=0; dp[u][1]=p[u]; for(int i=head[u];i;i=e[i].nxt) { int to=e[i].to; if(to==fa||vis[to]) continue; dfs(u,to); dp[u][0]+=max(dp[to][0],dp[to][1]); dp[u][1]+=dp[to][0]; } } int main() { isfind=0; //freopen("lys.in","r",stdin); cin>>n; for(int i=1;i<=n;i++) cin>>p[i]; for(int i=1;i<=n;i++) { int u,v;cin>>u>>v; u++;v++; add(u,v); add(v,u); } cin>>k; build(-1,1); memset(vis,0,sizeof(vis)); dfs(0,s); ans=dp[s][0]; memset(vis,0,sizeof(vis)); dfs(0,t); ans=max(dp[s][0],dp[t][0]); printf("%.1lf",(double)ans*k); }
分类:
图论
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)