题目链接

https://www.luogu.org/problemnew/show/P2860

https://www.lydsy.com/JudgeOnline/problem.php?id=1718

分析

首先这题目的意思就是让任意两点之间至少有两条没有重复道路的路径,很显然,如果这个图不存在桥,就一定满足上述条件。

于是我们就是要求使这个图不存在桥需要连接的最小边数

如果把桥从图中去掉,很显然剩余的联通块中任意两点之间至少有两条没有重复道路的路径(当然也可能不是联通块而是孤立的点),对答案不会产生贡献,我们不妨就将这些联通块缩点,于是就原来的图就变成了一颗树。

然后思考题目要求,当每个节点的度为2时任意两点之间至少有两条没有重复道路的路径,因为此时任意节点都有两条不同道路可走,于是用贪心的思想我们让度数为\(1\)的先互相连接,所以计算出树中的叶节点个数\(x\),\(\lceil\frac{x}{2}\rceil\)就是答案

注意

好象没什么注意的,不过我太菜把\(edge [j] .to\)写成\(edge [i] .to\)查了好久的错

代码


#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <cctype>
#include <cmath>
#include <map>
#include <queue>
#define ll long long
#define ri register int
using namespace std;
const int maxn=5005;
const int maxm=10005;
const int inf=0x7fffffff;
template <class T>inline void read(T &x){
x=0;int ne=0;char c;
while(!isdigit(c=getchar()))ne=c=='-';
x=c-48;
while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+c-48;
x=ne?-x:x;
return ;
}
struct Edge{
int ne,to;
}edge[maxm<<1];
int h[maxn],num_edge=0;
inline void add_edge(int f,int to){
edge[++num_edge].ne=h[f];
edge[num_edge].to=to;
h[f]=num_edge;
return ;
}
int n,m;
int dfn[maxn],low[maxn],tot=0;
bool bridge[maxm];
void tarjan(int now,int in_edge){//所在边的标号
int v;dfn[now]=low[now]=++tot;
for(ri i=h[now];i;i=edge[i].ne){
v=edge[i].to;
if(!dfn[v]){
tarjan(v,i);
low[now]=min(low[now],low[v]);
if(dfn[now]<low[v]){
bridge[i]=bridge[i^1]=true;//是桥
bb++;
}
}
else if(i!=(in_edge^1)){//如果不是在同一条无向边的对应边
low[now]=min(low[now],dfn[v]);
}
}
return ;
}
int num=0;//联通块的数量
int in_block[maxn];//各点所在联通块的标号
bool g[maxn][maxn];//重构后的图(储存)
void Contraction_Point(int now){//缩点
int v;in_block[now]=num;
for(ri i=h[now];i;i=edge[i].ne){
v=edge[i].to;
if(!bridge[i]&&!in_block[v]){
Contraction_Point(v);
}
}
return ;
}
int du[maxn];
inline void solve(){
int ans=0,x,y;
memset(g,0,sizeof(g));
for(ri i=1;i<=n;i++){
x=in_block[i];
for(ri j=h[i];j;j=edge[j].ne){
y=in_block[edge[j].to]; //太坑了
g[x][y]=g[y][x]=1;
}
}
memset(du,0,sizeof(du));
for(ri i=1;i<=num;i++){
for(ri j=1;j<=num;j++){
if(i!=j&&g[i][j]){du[j]++;
}
}
}
for(ri i=1;i<=num;i++){
if(du[i]==1)ans++;
}
printf("%d",(int)ceil(ans/double(2)));
return ;
}
int main(){
int x,y;
read(n),read(m);
num_edge=1;
for(ri i=1;i<=m;i++){
read(x),read(y);
add_edge(x,y);
add_edge(y,x);
}
memset(bridge,0,sizeof(bridge));
tarjan(1,0);
memset(in_block,0,sizeof(in_block));
for(ri i=1;i<=n;i++){
if(!in_block[i]){
num++;
Contraction_Point(i);
}
}
solve();
return 0;
}

最新文章

  1. 51Nod-1091 线段的重叠
  2. Codeforces 747D:Winter Is Coming(贪心)
  3. 剑指offer-二叉树的深度
  4. Linux:宿主机通过桥接方式连接的VMware内部Linux14.04虚拟机(静态IP)实现上网方案
  5. noi 8780 拦截导弹
  6. UnityShader之固定管线Fixed Function Shader【Shader资料3】
  7. 使用grunt打包前端代码
  8. C# 反射创建对象,包括创建引用外部程序集类的实例
  9. 【LeetCode】Best Time to Buy and Sell Stock IV
  10. java_接口和抽象类的区别
  11. docker遇到超时
  12. 《Java编程思想》读书笔记-第一个Java程序
  13. JAVA枚举带赋值
  14. python之路--线程的其他方法
  15. jQuery插件slider实现图片轮播
  16. [颜色知识] 潘通色卡、CMYK、RGB、 ARGB...
  17. [15]Windows内核情景分析 --- 权限管理
  18. 【译】在Asp.Net Core 中使用外部登陆(google、微博...)
  19. Spring源码解析 – @Configuration配置类及注解Bean的解析
  20. 简明python教程 --C++程序员的视角(五):面向对象的编程

热门文章

  1. aop备忘
  2. 数据库 | SQL查询&amp;LIMIT的用法
  3. Go项目的测试代码3(测试替身Test Double)
  4. Java 实现判断 主机是否能 ping 通
  5. 【Flink】flink执行jar报错:java.io.IOException: Error opening the Input Split file 或者 java.io.FileNotFoundException
  6. 小程序插件使用wx.createSelectorQuery()获取不到节点信息
  7. python3 速查参考- python基础 7 -&gt; 函数编程之 装饰器、生成器
  8. 求帮助 html5三次贝塞尔曲线问题
  9. Tensorflow之实现物体检测
  10. Elasticsearch基础入门,详情可见官方文档