[图论记录]arc143d bridges
题意:给定 个点和 ,选择让 连 或 连 ,以最小化图中桥的个数。
有种技巧叫拆点,把一个点拆成入点和出点,看这个形式非常像拆点,于是先想想合并。
若有 个点,连上所有 和 ,是桥的边在原图中只能是桥(路径唯一),抛出结论:可以通过构造,让其他边均不是桥。
如果现在在看一个连通块,只需要通过把边重定向以使得这一块强连通,即可。
考虑去掉那些桥后一个一个连通块处理:顺着 dfs 树走下去,遇到返祖边向上定向,否则向下定向,即得。
以前听说过拆点这个想法,但这是第一次见到,甚至连可以合并两个点都没想到,只能说是发散思维的极大不足了。确实想到了某种 与 间奇怪的对应关系,但“桥”导致往 tarjan 上想,这是复杂化了问题。
#include <cstdio>
using namespace std;
const int M = 5000005;
struct edge{
int to, nxt;
}e[M];
int head[M], cnt1 = 1;
void link(int u, int v){
e[++cnt1] = {v, head[u]}; head[u] = cnt1;
}
int n, m, a[M], b[M], dir[M]; bool vis[M], vis1[M];
void dfs(int u, int f){
if(vis1[u]) return; vis1[u] = 1;
for(int i = head[u]; i; i = e[i].nxt){
// printf("u=%d i=%d\n", u, i);
int v = e[i].to; if((i ^ 1) == f || vis[i]) continue;
vis[i^1] = vis[i] = 1; dir[i] = 1; dir[i^1] = 0; dfs(v, i);
}
}
int main(){
scanf("%d %d", &n, &m);
for(int i = 1; i <= m; i++) scanf("%d", &a[i]);
for(int i = 1; i <= m; i++) scanf("%d", &b[i]);
for(int i = 1; i <= m; i++) link(a[i], b[i]), link(b[i], a[i]);
for(int i = 1; i <= n; i++) if(!vis1[i]) dfs(i, 0);
for(int i = 1; i <= m; i++){
printf("%d", dir[i << 1]);
}
}
作者:purplevine
出处:https://www.cnblogs.com/purplevine/p/16428602.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
本文来自博客园,作者:purplevine,转载请注明原文链接:https://www.cnblogs.com/purplevine/p/16428602.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端