首页 > 其他分享 >codechef Starters73

codechef Starters73

时间:2023-01-12 16:23:25浏览次数:77  
标签:一条 Starters73 int 路径 新加 端点 dp codechef

https://www.codechef.com/START73A?order=desc&sortBy=successful_submissions

Hamiltonian Tree

手玩一下走哈密顿路的过程,一定是,走一条树上路径,然后走过新加的边,再到另一条树上路径,然后走完,然后再走新加的边。

为啥?因为你一条路径走完了,那你不可能走回头路,所以你只能通过新加的边到达另一条路径。

再者,我们注意到,树上路径的任意两条之间点集无交,且所有的路径的点集的并为全集 \(n\)。

也就是说,每个点仅存在于一条路径当中。

考虑最小化新加边,因为有路径数-1=新加边,因此即为最小化路径数。

考虑一个点,要么孤立作为一条路径,要么为路径的两端,要么为路径的中间。其度数对应 \(0,1,2\)。考虑两条路径如果要并起来,显然应该是他们存在两个端点的父亲是一样的,然后通过父亲把他们串起来,因此是可以树上 dp 的,因为我们对于当前点,只需要考虑孤立/连接以某个儿子为端点的一条路径,当前点作为端点/当前点作为中继点,串联起两个儿子为端点的路径。

考虑设 \(dp(u,0/1/2)\) 为 \(u\) 的子树内,当前 \(u\) 点对应哪种情况,所划分出的最小路径数。

转移就很显然啦。

#include <bits/stdc++.h>
#define int long long 
#define pb push_back
#define cal(x) (min(dp[(x)][0],min(dp[(x)][1],dp[(x)][2])))
using namespace std;
const int N=(int)(2e5+5),inf=(int)(2e9);
vector<int>g[N];
int n,dp[N][3];

void clr() {
	for(int i=1;i<=n;i++) g[i].clear(),dp[i][0]=dp[i][1]=dp[i][2]=0;
}

void dfs(int x,int ff) {
	for(int y:g[x]) {
		if(y==ff) continue ;
		dfs(y,x);
	}
	dp[x][0]=dp[x][1]=dp[x][2]=0;
	int res=0;
	for(int y:g[x]) {
		if(y==ff) continue ;
		res+=cal(y);
	}
	dp[x][0]=res+1;
	dp[x][1]=dp[x][2]=inf;
	for(int y:g[x]) {
		if(y==ff) continue ;
		dp[x][1]=min(dp[x][1],min(dp[y][0],dp[y][1])+res-cal(y));
	}
	int mi1=inf,mi2=inf;
	for(int y:g[x]) {
		if(y==ff) continue ;
		int qwq=min(dp[y][0],dp[y][1])-cal(y);
		if(qwq<mi1) mi2=mi1,mi1=qwq;
		else if(qwq<mi2) mi2=qwq;
	}
	if(mi2!=inf) {
		dp[x][2]=res+mi1+mi2-1;
	}
}

void sol() {
	cin>>n;
	for(int i=1;i<n;i++) {
		int x,y; cin>>x>>y;
		g[x].pb(y); g[y].pb(x);
	}
	dfs(1,0);
	int ans=cal(1);
	cout<<ans-1<<'\n';
	clr();
}

signed main() {
	cin.tie(0); ios::sync_with_stdio(false);
	int T; cin>>T; while(T--) sol();
	return 0;
} 

标签:一条,Starters73,int,路径,新加,端点,dp,codechef
From: https://www.cnblogs.com/xugangfan/p/17046992.html

相关文章

  • Codechef 2500+ problems
    TAEDITOR题目描述你需要维护一个字符串,支持插入字符串和查询子串。大体思路题解给的是BIT。然而事实上,这题相当于维护一个序列,支持区间插入和区间查询。这就是文艺......
  • Codechef-Cringe Queries
    这题的代码很短,但是建模很有思维含量,好题,记录一下题意:给定n,q,表示一个数组长度为n(初始下标从1开始),初始时全为0总共有q种操作,每个操作给定一个区间[l,r]表示可以将......
  • CodeChef Match the Streams
    题目链接:​​传送门​​题目中的pdf翻译:题目描述:给定两个序列和。定义序列和的相似度为满足的下标的数量。你需要回答个询问。每个询问给定参数,你需要将更改为,然后计算序......
  • CodeChef SHGAME
    #include<bits/stdc++.h>#defineintlonglongusingnamespacestd;inttong1[2323233],tong2[2323233];signedmain(){intT;cin>>T;while(T--)......