F. Vlad and Unfinished Business_树上dp
F. Vlad and Unfinished Business
题目大意:
在一棵树上,给出起点终点,和若干个标记点。现在要从起点开始,经过所有标记点后回到终点。问最短路程。
思路和代码:
一开始看到题目没什么想法就搁置了,仔细想想发现能做。下面给出我的想法。
先找出起点到终点的路径,因为这是一棵树所以路径是唯一的。
然后我们只要设置dp数组以i为根,走完该子树所有标记点并回来的最短。那么我们只要在回溯时进行递推即可。转移方程比较简单:
dp[now] = dp[now] + dp[nxt] + 2
最后的ans就是se路径长度加上dpi。
int n , m , k ;
int s , e ;
map<int , bool> inpath ;
void dfs(int now , int pre , vct<vct<int> >&eg , vct<int> &dp , vct<bool> &mk){
for(auto nxt : eg[now]){
if(nxt == pre || inpath[nxt]) continue ;
dfs(nxt , now , eg , dp , mk) ;
if(dp[nxt] || mk[nxt]) dp[now] += dp[nxt] + 2 ;
}
}
int ans ;
bool finde ;
vct<int> path ;
void getpath(int now , int pre , vct<vct<int> >&eg){
if(now == e) finde = 1 ;
for(int nxt : eg[now]){
if(nxt == pre || finde) continue ;
getpath(nxt , now , eg ) ;
}
if(finde){
path.pb(now) ;
inpath[now] = 1 ;
}
}
void solve(){
cin >> n >> k >> s >> e ;
vct<vct<int> > eg(n + 1) ;
vct<int> dp(n + 1 , 0) ;//以这个点为根,其子树中走遍所有点再回到 该点的最短路径
vct<bool> mk(n + 1 , 0) ;
rep(i , 1 , k){
int u ; cin >> u ;
mk[u] = 1 ;
}
rep(i , 1 , n - 1){
int u , v ; cin >> u >> v ;
eg[u].pb(v) ;
eg[v].pb(u) ;
}
ans = 0 ;
finde = 0 ;
path.clear() ;
inpath.clear() ;
getpath(s , -1 , eg) ;
ans += path.size() - 1 ;
for(auto x : path){
dfs(x , -1 , eg , dp , mk) ;
ans += dp[x] ;
}
cout << ans << "\n" ;
}//code_by_tyrii
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端