P6743 [BalticOI 2014 Day2] Senior Postmen 题解
题目描述
P6743 BalticOI 2014 Day2 Senior Postmen
题目解法
看到题目想到直接爆搜。
根据题意,只要找出所有互不相交的简单环即可。题目保证了合法性。
跑 dfs,每次到达一个点 \(u\) 就将其放入栈 \(stk\) 中。如果栈 \(stk\) 中已经有点 \(u\),那么就弹栈。
同时每经过一条边 \(i\),那么就将 \(vis_i\) 设为 \(1\),防止重复计数。
做法和 Tarjan 求联通分量有些相似。
所以:
vector<int> stk;
int ins[maxn], vis[maxn<<1];
void dfs(int u)
{
for(int i=head[u];i;i=nxt[i])
{
if(vis[i]) continue;
vis[i]=vis[i^1]=1;
dfs(to[i]);
}
if(ins[u])
{
while(stk.back()!=u)
{
cout<<stk.back()<<' ';
ins[stk.back()]=0;
stk.pop_back();
}
return cout<<stk.back()<<'\n', void();
}
ins[u]=1;
stk.emplace_back(u);
}
喜提 \(\color{orange} \textsf{55pts}\)。TLE on #22 #24
仔细一想,因为每条边只能被使用一次,所以每次可以将 \(head_u\) 更新为 \(nxt_i\)。
修改后:(dfs 函数第三行)
for(int i=head[u];i;i=head[u]=nxt[i])
还是 \(\color{orange} \textsf{55pts}\)。只是变成了 TLE on #22
经过一通乱改,最后采取在 dfs 其余节点之前将 \(head_u\) 更新为 \(nxt_i\),所以循环处将 \(i\) 更新为 \(head_u\)。
修改后:(以及写的极丑的栈)
int stk[maxn], *top=stk;
int ins[maxn], vis[maxn<<1];
void dfs(int u)
{
for(int i=head[u];i;i=head[u])
{
head[u]=nxt[i];
if(vis[i]) continue;
vis[i]=vis[i^1]=1;
dfs(to[i]);
}
if(ins[u])
{
while(*top!=u)
{
cout<<*top<<' ';
ins[*top--]=0;
}
return cout<<*top<<'\n', void();
}
ins[*++top=u]=1;
}
成功 \(\color{green} \textsf{AC}\)。
Code
#include<bits/stdc++.h>
using namespace std;
#define maxn 500005
int head[maxn], to[maxn<<1], nxt[maxn<<1], tot=1;
void link(int u, int v)
{
to[++tot]=v;
nxt[tot]=head[u];
head[u]=tot;
}
int stk[maxn], *top=stk;
int ins[maxn], vis[maxn<<1];
void dfs(int u)
{
for(int i=head[u];i;i=head[u])
{
head[u]=nxt[i];
if(vis[i]) continue;
vis[i]=vis[i^1]=1;
dfs(to[i]);
}
if(ins[u])
{
while(*top!=u)
{
cout<<*top<<' ';
ins[*top--]=0;
}
return cout<<*top<<'\n', void();
}
ins[*++top=u]=1;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int n,m;
cin>>n>>m;
for(int i=1, u, v;i<=m;i++)
{
cin>>u>>v;
link(u, v);
link(v, u);
}
dfs(1);
}

浙公网安备 33010602011771号