首页 > 其他分享 >P6628 [省选联考 2020 B 卷] 丁香之路 题解

P6628 [省选联考 2020 B 卷] 丁香之路 题解

时间:2022-11-11 21:34:18浏览次数:67  
标签:度数 连边 连通 一个点 P6628 题解 奇数 偶数 联考

图论、贪心好题。

枚举每一个朋友,设一个朋友从 \(s\) 出发,到 \(t\) 结束。那么如果用边来表示其行动轨迹,必然是 \(s,t\) 有奇数度,其它点均为偶数度。如果在 \(s,t\) 之间连一条边,我们只要找到一种连边的方式使得每个点都是偶数度就可以了。容易知道如果每个点都是偶数度并且 \(s,t\) 连通,这两点之间必然存在一条合法路径。

开有丁香花的道路必须经过,所以先把这些边连上。现在我们的目的是:花最小的代价连边,使得每一个点的度数为偶数,并且确保 \(s,t\) 和 所有 的边连通。

这个时候就要想一种贪心策略。我们首先保证每个点的度数为偶数,可以在遇到一个点的度数为奇数时,把它与后面第一个度数为奇数的点之间连边。因为每一条边都会贡献两个度数,所以最终一定能使得每一个点的度数均为偶数。但是在确保连通性的情况下有一个更优策略:把度数为奇数的点直接向下一个点连边。这样边权和没有改变,但是连通了更多的点。

确保所有边连通,则可以把所有连通块缩点后跑最小生成树。

最后是计算贡献。因为最小生成树建出来后要保证度数,所以最小生成树的边要取两倍。建图时只需要保证相邻的连通块之间有最小边,就可以保证最优。代码中给出了一种较为简易的实现方式。

代码如下:

#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
const int N=2505;
int n,m,s,ind[N],iid[N],fa[N],ffa[N];ll sum,ans;
struct Edge{int u,v,w;};vector<Edge>e;
bool operator<(const Edge&A,const Edge&B){return A.w<B.w;}
int get(int x){return x==fa[x]?x:fa[x]=get(fa[x]);}
inline void merge(int x,int y){fa[get(x)]=get(y);}
int main(){
	scanf("%d%d%d",&n,&m,&s);
	for(int i=1;i<=n;i++)fa[i]=i;
	for(int i=1,u,v;i<=m;i++){
		scanf("%d%d",&u,&v);sum+=abs(u-v);
		iid[u]++;iid[v]++;merge(u,v);
	}
	for(int i=1;i<=n;i++)ffa[i]=fa[i];
	for(int t=1;t<=n;t++){
		for(int i=1;i<=n;i++)fa[i]=ffa[i],ind[i]=iid[i];
		ind[s]++;ind[t]++;merge(s,t);ans=0;
		for(int i=1;i<=n;i++)if(ind[i]&1){
			ind[i]++;ind[i+1]++;merge(i,i+1);ans++;
		}
		e.clear();
		for(int i=1,j=0;i<=n;i++)if(ind[i]){
			if(j&&get(i)!=get(j))e.push_back({j,i,i-j});
			j=i;
		}
		sort(e.begin(),e.end());
		for(Edge E:e){
			if(get(E.u)!=get(E.v))merge(E.u,E.v),ans+=(E.w<<1);
		}
		printf("%lld ",ans+sum);
	}
	return 0;
}

标签:度数,连边,连通,一个点,P6628,题解,奇数,偶数,联考
From: https://www.cnblogs.com/hihihi198/p/16882089.html

相关文章

  • CF464D World of Darkraft - 2 题解
    期望好题,可以帮助我们更加深入地了解期望。由于\(k\)种装备相同,所以只要计算卖掉一种装备得到的金币期望乘以\(k\)就行了。为了避免讨论当前状态的概率,期望DP通常......
  • CF1316E Team Building 题解
    可能更好的阅读体验题目传送门题目大意传送门你需要组建一支排球队。为了组织一支排球队,你需要为队伍里的\(p\)个不同的位置,从\(n\)个人中选出\(p\)个人,且每个位......
  • CF1735E题解
    钦定\(p_1=0,p_2>0\),不难证明如果有解则一定存在\(p_2>p_1\)的解。考虑枚举和\(d_{1,1}\)是相同楼房,则\(p_2\)对于每一种情况有两种可能的位置:\(d_{1,1}+d_{2,i}\)......
  • P3188 [HNOI2007]梦幻岛宝珠 题解
    一道不错的dp题,下令原背包容量为\(m\)。注意到\(w_i=a\times2^b\)中\(a,b\)都比较小,尝试按照\(a\)或者\(b\)分组然后合并,但是显然如果我们按照\(a\)分组就......
  • 汉诺塔问题及其变种问题解法(cpp版本)
    普通汉诺塔问题1.问题描述有三个柱子A、B、C,A柱子上有n个圆盘,圆盘的大小不等,大圆盘的在下,小圆盘的在上。将A柱子上的圆盘全部移动到C柱子上。每次只能移动一个圆盘,而且......
  • 【题解】P2260 [清华集训2012]模积和(数学,整除分块)
    【题解】P2260[清华集训2012]模积和比较简单的一道推式子的题。(清华集训居然会出这种水题的吗)题目链接P2260[清华集训2012]模积和题意概述求\[\sum_{i=1}^{n}\sum......
  • 【题解】CF1485C Floor and Mod(二分答案,整除分块)
    【题解】CF1485CFloorandModemmm……NOIP考前两周,跟CSP考前一样(虽然最后并没有去考),写篇题解增加以下RP(雾)。提供一篇思路大体和题解区相同但用了二分写法的题解。......
  • P2254 [NOI2005] 瑰丽华尔兹 题解
    注意到可以设朴素转移方程\(f_{t,i,j}\)表示\(t\)时刻钢琴在\((i,j)\)时的最长滑动距离,这样复杂度是\(O(nmt)\)的,过不去。不过听说加点奇怪的优化能过?考虑一段时......
  • MySQL慢查询(下):问题解决,应用总结
    上篇回顾继上两篇:​​MySQL慢查询(上):你知道为啥会慢么?​​​​MySQL慢查询(中):正确的处理姿势,你get到了吗?​​在以上两篇内容中,我们一起探索了这些内容:SQL执行过程查询SQL为什......
  • 「题解」Codeforces 1098D Eels
    暴力是,每次挑出最小的两个合并。需要观察到没有产生贡献的次数很小。考虑最小的那个数的大小,如果一次合并没有产生贡献,那么最小的数至少\(\times2\).所以最多会有\(\mat......