标签:拓扑 add bool rac == || 起点 收藏 没有
\(\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;
}
如有哪里讲得不是很明白或是有错误,欢迎指正
如您喜欢的话不妨点个赞收藏一下吧
标签:拓扑 add bool rac == || 起点 收藏 没有
原文地址:https://www.cnblogs.com/Morning-Glory/p/11437909.html