CF858F Wizard's Tour

也许更好的阅读体验

\(\mathcal{Description}\)

给定一张 \(n\) 个点 \(m\) 条边的无向图,每条边连接两个顶点,保证无重边自环,不保证连通。

你想在这张图上进行若干次旅游,每次旅游可以任选一个点 \(x\) 作为起点,再走到一个与 \(x\) 直接有边相连的点 \(y\),再走到一个与 \(y\) 直接有边相连的点 \(z\) 并结束本次旅游。

作为一个旅游爱好者,你不希望经过任意一条边超过一次,注意一条边不能即正向走一次又反向走一次,注意点可以经过多次,在满足此条件下,你希望进行尽可能多次的旅游,请计算出最多能进行的旅游次数并输出任意一种方案。

\(\mathcal{Solution}\)

20分思路

先提供一个比较傻且只能得20分的思路
就是我们把每条边看做是一个点,距离为一的点之间连一条边
于是问题就变成了求最大匹配了
不过这样会把边的条数大大增大.....
妥妥的TLE

100分思路

若仅是一棵树,那此题的做法还是很显然的
要保证边用的最多,按照树的深度从小到大考虑,即按照拓扑序将能匹配的匹配就是正确的

若不仅是一棵树,我们随便按照一种方式把它的生成树建出来
这样就有非树边和树边,对于每个点,我们先将其与父亲的边不考虑
设其周围有\(n\)条边
若\(n\)为偶数,就可以把它们两两搭配,有\(\frac{n}{2}\)种方法
若\(n\)为奇数,就拿一条边与其与父亲的边搭配,剩下的两两搭配
显然,这样做除了在根节点剩下一条边,其他的边都会被用到

\(\mathcal{Code}\)

实现部分说一下吧
我觉得我打得比其它人的简洁一些吧
大部分人用了一个\(vector\)去记录哪些边
实际上,我们可以直接把这些边匹配
用\(f[x]\)表示是否有一条与\(x\)相连且还没有匹配的边
每次拿到新边看看有没有为匹配的边,有的话它们就匹配
注意一条边只需考虑一次

/*******************************
Author:Morning_Glory
LANG:C++
Created Time:2019年08月30日 星期五 09时08分56秒
*******************************/
#include <cstdio>
#include <fstream>
#include <cstring>
using namespace std;
const int maxn = 1000006;
//{{{cin
struct IO{
    template<typename T>
    IO & operator>>(T&res){
        res=0;
        bool flag=false;
        char ch;
        while((ch=getchar())>'9'||ch<'0')    flag|=ch=='-';
        while(ch>='0'&&ch<='9') res=(res<<1)+(res<<3)+(ch^'0'),ch=getchar();
        if (flag)    res=~res+1;
        return *this;
    }
}cin;
//}}}
int n,m,u,v,cnt,ans;
int head[maxn],nxt[maxn],to[maxn];//edge
int a[maxn],b[maxn],c[maxn],f[maxn];//ans
bool vis[maxn];
//{{{add
void add (int u,int v)
{
    nxt[cnt]=head[u],head[u]=cnt,to[cnt++]=v;
}
//}}}
//{{{dfs
void dfs (int x)
{
    vis[x]=true;
    for (int e=head[x];~e;e=nxt[e]){
        int te=to[e];
        to[e]=to[e^1]=0;
        if (te){
            if (!vis[te])   dfs(te);
            if (f[te])  a[++ans]=x,b[ans]=te,c[ans]=f[te],f[te]=0;
            else if (f[x])  a[++ans]=f[x],b[ans]=x,c[ans]=te,f[x]=0;
            else    f[x]=te;
        }
    }
}
//}}}
int main()
{
    memset(head,-1,sizeof(head));
    cin>>n>>m;
    for (int i=1;i<=m;++i)  cin>>u>>v,add(u,v),add(v,u);
    vis[0]=true;
    for (int i=1;i<=n;++i)
        if (!vis[i])    dfs(i);
    printf("%d\n",ans);
    for (int i=1;i<=ans;++i)    printf("%d %d %d\n",a[i],b[i],c[i]);
    return 0;
}

如有哪里讲得不是很明白或是有错误,欢迎指正
如您喜欢的话不妨点个赞收藏一下吧

CF858F Wizard's Tour

原文地址:https://www.cnblogs.com/Morning-Glory/p/11437909.html

时间: 2024-08-30 17:54:35

CF858F Wizard's Tour的相关文章

「CF858F」 Wizard&#39;s Tour

传送门 Luogu 解题思路 首先对于树的情况,我们很显然有一种贪心策略: 对于每一个节点先匹配子树,然后在还可以匹配的儿子间尽可能匹配,要是多出来一个就往上匹配. 推广到图的情况... 我们在图的生成树上 \(\text{DFS}\) ,即时删边,防止重复访问. 然后记录一个 \(f[x]\),表示直接与 \(x\) 节点并且还可以用来匹配的点. 那么我们直接一边 \(\text{DFS}\) ,一边匹配就好了. 最后输出答案即可. 细节注意事项 没什么细节,就是要仔细想一想 参考代码 #in

九月流水账

9.1 - 9.19 兵荒马乱 诶诶诶诶诶诶诶诶诶诶诶诶诶诶诶诶..........加加加加加加加加加加加加加油呀 --- 不萌 的 分割线 ----------------------- 上课项目上课项目上课项目..好多时候 累的 只想 睡觉 瘦了五斤 还把自己搞进医院挂了两天水qaq 一身毛病 都被召唤粗来的感觉...qwq flag 立在这里 身体健康比什么都重要 ! 多吃菜水果多喝水早点睡! 9.20 p站的画 终于 收到了第一个喜欢 !开心 !总浏览量 也 1k+ 了 !然鹅第二天 就

2019-1005至1007总结

咕的太多了,赶紧补补. 前面的就写写题解,最近的再写总结. 10/05$Night$ T1 模拟,我采取的方法是记录方向和尾部节点. 但是如果使用$vector$记录路径最后$clear$或是直接用$map$会好一些. 我用了一个二维数组,于是T掉了. 后来考完后把数组开小后AC 没人需要代码吧…… 还是放一个: #include <algorithm> #include <iostream> #include <cstring> #include <cstdio

F - Free DIY Tour(动态规划)

这道题也可以用深搜做,可以深搜本来就不熟,好久没做早忘了,明天看看咋做的 Description Weiwei is a software engineer of ShiningSoft. He has just excellently fulfilled a software project with his fellow workers. His boss is so satisfied with their job that he decide to provide them a free

HDU 1853 Cyclic Tour(最小费用最大流)

Cyclic Tour Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/65535 K (Java/Others) Total Submission(s): 1879    Accepted Submission(s): 938 Problem Description There are N cities in our country, and M one-way roads connecting them. Now L

UVALive 4848 Tour Belt

F - Tour Belt Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Submit Status Practice UVALive 4848 Description Korea has many tourist attractions. One of them is an archipelago (Dadohae in Korean), a cluster of small islands sca

POJ 2135 Farm Tour &amp;&amp; HDU 2686 Matrix &amp;&amp; HDU 3376 Matrix Again 费用流求来回最短路

累了就要写题解,最近总是被虐到没脾气. 来回最短路问题貌似也可以用DP来搞,不过拿费用流还是很方便的. 可以转化成求满流为2 的最小花费.一般做法为拆点,对于 i 拆为2*i 和 2*i+1,然后连一条流量为1(花费根据题意来定) 的边来控制每个点只能通过一次. 额外添加source和sink来控制满流为2. 代码都雷同,以HDU3376为例. #include <algorithm> #include <iostream> #include <cstring> #in

Codeforces 490F Treeland Tour(离散化 + 线段树合并)

题目链接 Treeland Tour 题目就是让你求树上LIS 先离散化,然后再线段树上操作.一些细节需要注意一下. #include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i) typedef long long LL; const int N =

hdoj 3488 Tour 【最小费用最大流】【KM算法】

Tour Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others) Total Submission(s): 2299    Accepted Submission(s): 1151 Problem Description In the kingdom of Henryy, there are N (2 <= N <= 200) cities, with M (M <= 3000