这个专题实属虐心…各种debug搞到自闭
不过进步就是在自闭中产生的…
后面被反向边逼迫使用了链式前向星建图(双修?)

1.POJ 1236 Network of Schools

任务一:求出入度为0的连通分量数量
任务二:求加多少条边能让整个图强连通
对于第二问,因为要使整个图强连通,贪心的拿每一个出度为0的点对入度为0的点加边,这样下来最小的加边数就是max(入度,出度)

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <stdlib.h>
#include <vector>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
#include <set>
using namespace std;
const int maxn=1e3+5,maxm=1e3+5;
int n,m,chu[maxn];
int dfn[maxn],low[maxn],vis[maxn],z[maxn],color[maxn],cnt[maxn],ru[maxn],t,k,tot;
vector<int>e[maxm];
void tarjan(int u,int fa){dfn[u]=low[u]=++tot;z[++k]=u;//入栈 vis[u]=1;for(int i=0;i<e[u].size();i++){if(!dfn[e[u][i]]){tarjan(e[u][i],fa);low[u]=min(low[u],low[e[u][i]]);}else if(vis[e[u][i]]){low[u]=min(low[u],dfn[e[u][i]]);}}if(low[u]==dfn[u]){t++;//连通分量的标号 do{color[z[k]]=t;    //属于这个连通分量 cnt[t]++;         //记录这个环中有多少个点vis[z[k]]=0; k--;              //出栈 }while(u!=z[k+1]);}
}
int main(){cin>>n;for(int i=1;i<=n;i++){while(1){int v;scanf("%d",&v);if(v==0)break;e[i].push_back(v); }}for(int i=1;i<=n;i++){if(!dfn[i])tarjan(i,i);}int ans=0,maxx=0;for(int i=1;i<=n;i++){for(int j=0;j<e[i].size();j++){if(color[i]!=color[e[i][j]]){ru[color[e[i][j]]]++;chu[color[i]]++;}}}int x=0,y=0;for(int i=1;i<=t;i++){if(ru[i]==0)x++;if(chu[i]==0)y++;}if(t==1)cout<<x<<endl<<"0";else cout<<x<<endl<<max(x,y);return 0;
}

2.UVA 315 Network

求割点
uva读入恶心人

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <stdlib.h>
#include <vector>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
#include <set>
using namespace std;
const int maxn=2e4+5,maxm=2e4+5;
int n,m;
bool cut[maxn];
int dfn[maxn],low[maxn],vis[maxn],z[maxn],color[maxn],cnt[maxn],du[maxn],t,k,tot;
vector<int>e[maxm];
void tarjan(int u,int root){//root代表此树的根 int child=0;dfn[u]=low[u]=++tot;for(int i=0;i<e[u].size();i++){int v=e[u][i];if(!dfn[v]){tarjan(v,root);low[u]=min(low[u],low[v]);if(low[v]>=dfn[u]&&u!=root)cut[u]=true;if(u==root)child++;}low[u]=min(low[u],dfn[v]);}if(u==root&&child>=2){cut[root]=true;}
}
void init(int n){memset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low));memset(cut,false,sizeof(cut));for(int i=0;i<=n;i++){e[i].clear();}
}
int main(){int u,v;char c;while(cin>>n){if(n==0)break;init(n);while (scanf("%d", &u), u) {while (scanf("%c", &c), c != '\n') {scanf("%d", &v);e[u].push_back(v);e[v].push_back(u);}}for(int i=1;i<=n;i++){if(!dfn[i])tarjan(i,i);}int ans=0;for(int i=1;i<=n;i++){if(cut[i])ans++;}cout<<ans<<endl;}return 0;
}

3.UVA 796 Critical Links

求桥
uva读入再次恶心人
对于求桥有不同的写法,有时候会出现玄学错误…

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <stdlib.h>
#include <vector>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
#include <set>
using namespace std;
const int maxn=2e5+5,maxm=5e5+5;
int n,m;
int dfn[maxn],low[maxn],t,k,tot;
vector<int>e[maxm];
struct edge{int u,v;
}qiao[maxm];
bool cmp(edge a,edge b){if(a.u==b.u)return a.v<b.v;return a.u<b.u;
}
void tarjan(int u,int root){//root代表此树的根 dfn[u]=low[u]=++tot;for(int i=0;i<e[u].size();i++){int v=e[u][i];if(!dfn[v]){tarjan(v,u);low[u]=min(low[u],low[v]);if(low[v]>dfn[u]){t++;qiao[t].u=min(u,v);qiao[t].v=max(u,v);}}else if(v!=root)low[u]=min(low[u],dfn[v]);}return;
}
void init(int n){t=0;tot=0;k=0;memset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low));for(int i=0;i<=n;i++){e[i].clear();}
}
int main(){while(cin>>n){init(n);int u,v,num;char c1,c2;for(int i=1;i<=n;i++){cin>>u>>c1>>num>>c2;u++;while(num--){cin>>v;v++;e[u].push_back(v);}}for(int i=1;i<=n;i++){if(!dfn[i])tarjan(i,0);}sort(qiao+1,qiao+1+t,cmp);printf("%d critical links\n",t);for(int i=1;i<=t;i++){printf("%d - %d\n",qiao[i].u-1,qiao[i].v-1);}cout<<endl;
}return 0;
}

4.POJ 3694 Network

求加边的过程中,桥的数量
正解应该是每次加边后求出lca,加入这条边之后这个环上面的边就都不是桥了
借鉴了大神的题解的方法,在求桥的过程中求出每个点的深度,然后用check函数将两个点逐渐跳到lca,并将路径上的桥消去

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <stdlib.h>
#include <vector>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
#include <set>
using namespace std;
const int maxn=2e5+5,maxm=4e5+5,inf=0x3f3f3f3f;
int dfn[maxn],low[maxn],fa[maxn],dep[maxn],qiao[maxn],n,m,t,tot;
vector<int>e[maxm*2];
void tarjan(int u,int root){dfn[u]=low[u]=++tot;for(int i=0;i<e[u].size();i++){int v=e[u][i];if(v==root)continue;if(!dfn[v]){fa[v]=u;dep[v]=dep[u]+1;tarjan(v,u);low[u]=min(low[u],low[v]);if(low[v]>dfn[u]){t++;qiao[v]=1;}}else low[u]=min(low[u],dfn[v]);}return;
}
void check(int u,int v){while(dep[u]>dep[v]){if(qiao[u])t--,qiao[u]=0;u=fa[u];}while(dep[v]>dep[u]){if(qiao[v])t--,qiao[v]=0;v=fa[v];}while(u!=v){if(qiao[u])qiao[u]=0,t--;if(qiao[v])qiao[v]=0,t--;u=fa[u];v=fa[v];}
}
void qibao(int n){memset(low,0,sizeof(low));memset(dfn,0,sizeof(dfn));memset(fa,0,sizeof(fa));memset(dep,0,sizeof(dep));memset(qiao,0,sizeof(qiao));t=tot=0;for(int i=0;i<=n;i++){e[i].clear();}
}
int main(){int n,m,u,v,tt=1;while(scanf("%d%d",&n,&m)!=EOF){if(n==0&&m==0)break;qibao(max(n,m));for(int i=1;i<=m;i++){scanf("%d%d",&u,&v);e[u].push_back(v);e[v].push_back(u);}cin>>m;for(int i=1;i<=m;i++){if(!dfn[i])tarjan(i,i);}printf("Case %d:\n",tt++);for(int i=1;i<=m;i++){scanf("%d%d",&u,&v);check(u,v);cout<<t<<endl;}cout<<endl;}return 0;
}

5.POJ 3177 Redundant Paths

问加多少条边可以让图成为双连通图
先缩点
入度为1的点数量为ans
答案为(ans+1)/2
这是怎么来的呢?将入度为1的点两两相连就可以了,所以点数为奇数的话要+1

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <stdlib.h>
#include <vector>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
#include <set>
using namespace std;
const int maxn=1e5+5,maxm=1e6+5,inf=0x3f3f3f3f;
int low[maxn],dfn[maxn],tot,k,t,z[maxn],head[maxm],len=1;
int color[maxm],ru[maxn];
struct edge{int v,nex;
}e[maxm];
void add_edge(int u,int v){e[++len].v=v;e[len].nex=head[u];head[u]=len;
}
void tarjan(int u,int root){dfn[u]=low[u]=++tot;z[++k]=u;for(int i=head[u];i;i=e[i].nex){int v=e[i].v;if(!dfn[v]){tarjan(v,i);low[u]=min(low[u],low[v]);}else if(i!=(root^1))low[u]=min(low[u],dfn[v]);}if(low[u]==dfn[u]){t++;//连通分量的标号 do{color[z[k]]=t;    //属于这个连通分量 k--;              //出栈 }while(u!=z[k+1]);}
}
int main(){int n,m;cin>>n>>m;for(int i=1;i<=m;i++){int u,v;cin>>u>>v;add_edge(u,v);add_edge(v,u);}tarjan(1,0);int ans=0;for(int u=1;u<=n;u++){for(int j=head[u];j;j=e[j].nex){int v=e[j].v;if(color[u]!=color[v])ru[color[v]]++;}}for(int i=1;i<=t;i++){if(ru[i]==1)ans++;}cout<<(ans+1)/2;
}

6.HDU 4612 Warm up

缩点建树+树的直径
缩点后得到一棵树
因为树上每条边都是桥,所以桥的数量=联通分量数-1
问加一条边能让桥的数量最少为多少
树的直径的上的桥最多
所以用桥的数量-树的直径即为答案

wa到哭,让我晚上整个人都清醒了

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <stdlib.h>
#include <vector>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
#include <set>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
const int maxn=2e5+5,maxm=2e6+5,inf=0x3f3f3f3f;
int low[maxn],dfn[maxn],tot,top,t,z[maxn],head[maxn],len,len2,d;
int color[maxn],head2[maxn],vis[maxn],ans,n,m;
struct edge{int v,nex;
}e[maxm],e2[maxm];
inline int read()
{int x=0,k=1; char c=getchar();while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();return x*k;
}
void init(){memset(head,-1,sizeof(head));memset(vis,0,sizeof(vis));memset(dfn,0,sizeof(dfn));tot=0,t=0,len=0,len2=0,top=0,d=0;
}
inline void add_edge(int u,int v){e[len].v=v;e[len].nex=head[u];head[u]=len++;
}
inline void add_edge2(int u,int v){e2[len2].v=v;e2[len2].nex=head2[u];head2[u]=len2++;
}
void build(){len2=0;memset(head2,-1,sizeof(head2));for(int u=1;u<=n;u++){for(int j=head[u];j!=-1;j=e[j].nex){int v=e[j].v;if(color[u]!=color[v]){add_edge2(color[u],color[v]);}}}
}
void tarjan(int u,int root){low[u]=dfn[u]=++tot;vis[u]=1;z[top++]=u;int flag=1;for(int i=head[u];i!=-1;i=e[i].nex){int v=e[i].v;if(v==root&&flag){flag=0;continue;}if(!dfn[v]){tarjan(v,u);low[u]=min(low[u],low[v]);}else if(vis[v]){low[u]=min(low[u],dfn[v]);}}if(low[u]==dfn[u]){t++;int v;while(1){v=z[top-1];top--;color[v]=t;vis[v]=0;if(v==u)break;}}
}
int dfs(int u,int fa){int d1=0,d2=0;for(int i=head2[u];i!=-1;i=e2[i].nex){int v=e2[i].v;if(v==fa)continue;int d=dfs(v,u)+1;if(d>d1)d2=d1,d1=d;else if(d>d2)d2=d;}ans=max(ans,d1+d2);return d1;
}
int main(){int u,v;while(scanf("%d%d",&n,&m)&&(n+m)){init();for(int i=1;i<=m;i++){u=read(),v=read();if(u==v)continue;add_edge(u,v);add_edge(v,u);}tarjan(1,-1);build();ans=0;dfs(1,-1);printf("%d\n",t-ans-1);}return 0;
}

7.HDU 4635 Strongly connected

给定一个有向图,求最大可以增加多少条边使得这个仍然不是强连通
首先要知道一点:完全图的边数为n*(n-1)
然后减去图中本来就有的m条边
再减去入度或出度为0的点能跟其他点连的边or被其他点连的边,即为最终答案

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <stdlib.h>
#include <vector>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
#include <set>
#define int long long
using namespace std;
const int maxn=1e5+5,maxm=1e5+5;
int n,m,chu[maxn],qq,a[maxn],b[maxn];
int dfn[maxn],low[maxn],vis[maxn],z[maxn],color[maxn],cnt[maxn],ru[maxn],t,k,tot;
vector<int>e[maxm];
void tarjan(int u){dfn[u]=low[u]=++tot;z[++k]=u;//入栈 vis[u]=1;for(int i=0;i<e[u].size();i++){if(!dfn[e[u][i]]){tarjan(e[u][i]);low[u]=min(low[u],low[e[u][i]]);}else if(vis[e[u][i]]){low[u]=min(low[u],dfn[e[u][i]]);}}if(low[u]==dfn[u]){t++;//连通分量的标号 do{color[z[k]]=t;    //属于这个连通分量 cnt[t]++;         //记录这个环中有多少个点vis[z[k]]=0; k--;              //出栈 }while(u!=z[k+1]);}
}
void init(int n){memset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low));memset(z,0,sizeof(z));memset(vis,0,sizeof(vis));memset(color,0,sizeof(color));memset(cnt,0,sizeof(cnt));memset(ru,0,sizeof(ru));memset(chu,0,sizeof(chu));memset(a,0,sizeof(a));memset(b,0,sizeof(b));for(int i=0;i<=n;i++){e[i].clear();}t=0;k=0;tot=0;
}
signed main(){int tt;cin>>tt;while(tt--){qq++;cin>>n>>m;init(max(n,m));for(int i=1;i<=m;i++){int u,v;scanf("%d%d",&u,&v);a[i]=u;b[i]=v;e[u].push_back(v);}for(int i=1;i<=n;i++){if(!dfn[i])tarjan(i);}for(int i=1;i<=n;i++){for(int j=0;j<e[i].size();j++){int u=color[i];int v=color[e[i][j]];if(u!=v){chu[u]++;ru[v]++;}}}int minv=n;for(int i=1;i<=t;i++){if(ru[i]==0||chu[i]==0)minv=min(minv,cnt[i]);}int ans=n*(n-1)-m-minv*(n-minv);if(t==1)printf("Case %lld: -1\n",qq);else printf("Case %lld: %lld\n",qq,ans);}return 0;
}

8.HDU 4685 Prince and Princess

夹带私货的题,二分图完美匹配+缩点,之后补(虽然会用最大流求最大匹配数)

9.HDU 4738 Caocao’s Bridges

又是一题坑的我爆炸的题
用之前的找桥的tarjan疯狂无敌爆炸wa
以后求桥都用这个 链式前向星+反向边来求
其实这个题很简单,求桥的过程中更新桥的最小权值就可以了,如果图本来就不连通就输出-1,特判最小权值为0,因为最少还是需要一个人去炸桥,所以为1

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <stdlib.h>
#include <vector>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
#include <set>
using namespace std;
const int maxn=2e4+5,maxm=2e6+5,inf=0x3f3f3f3f;
int n,m;
int dfn[maxn],low[maxn],k,tot,ans,tcnt,head[maxn],cnt;
int qiao[maxm];
struct edge{int v,w,nex;
}e[maxm];
inline void add(int u,int v,int w){e[++cnt].nex=head[u];e[cnt].v=v;e[cnt].w=w;head[u]=cnt;
}
void tarjan(int u,int root){//root代表此树的根 dfn[u]=low[u]=++tot;for(int i=head[u];i!=-1;i=e[i].nex){int v=e[i].v;if(!dfn[v]){tarjan(v,i);low[u]=min(low[u],low[v]);if(low[v]>dfn[u]){ans=min(ans,e[i].w);}}else if(i!=(root^1))low[u]=min(low[u],dfn[v]);}return;
}
void init(){tot=0;k=0;cnt=1;tcnt=0;ans=inf;memset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low));memset(head,-1,sizeof(head));
}
int main(){while(cin>>n>>m){if(n==0&&m==0)break;init();int u,v,w;for(int i=1;i<=m;i++){cin>>u>>v>>w;add(u,v,w);add(v,u,w);}for(int i=1;i<=n;i++){if(!dfn[i]){tarjan(i,0);tcnt++;}}if(tcnt>1)puts("0");else if(ans==inf)puts("-1");else if(ans==0)puts("1");else printf("%d\n",ans);}return 0;
}

刷题记录不是题解,写的十分简略,见谅qwq
自闭自闭自闭自闭自闭自闭…

刷题记录 kuangbin带你飞专题九:连通图相关推荐

  1. [kuangbin带你飞]专题九 连通图

    A. POJ 1236  Network of Schoolst 题意:有n个学校,每个学校都可以给它名单上的学校发送软件.然后现在问你至少需要给多少个学校发送软件. 思路:求出强连通分量的个数,每一 ...

  2. kuangbin带你飞专题合集

    题目列表 [kuangbin带你飞]专题一 简单搜索 [kuangbin带你飞]专题二 搜索进阶 [kuangbin带你飞]专题三 Dancing Links [kuangbin带你飞]专题四 最短路 ...

  3. “kuangbin带你飞”专题计划——专题十四:数论基础

    写在前面 1.目前还没啥写的.开始时间:2021-05-13(其实博客上看得到该博客创建时间的) 2.上一个专题刷的是网络流(博客总结),属于第一次接触.本来想的是一周特别高效,然后一周略划水,结果是 ...

  4. (2021-07-14~)“kuangbin带你飞”专题计划——专题十三:基础计算几何

    目录 前言 参考博客 自己总结的东西: 难度判断? 题目 1.[TOYS POJ - 2318 ](解决) 2.[Toy Storage POJ - 2398 ](解决) 3.[Segments PO ...

  5. $2019$ 暑期刷题记录 $2$(基本算法专题)

    $ 2019 $ 暑期刷题记录 $ 2 $ (基本算法专题) $ by~~wch $ $ BZOJ~1958~Strange~Towers~of~Hanoi $ (动态规划,递推) 题目大意: 求有 ...

  6. kuangbin带你飞 专题1-23 题单

    kuangbin大神,对于打过ACM比赛的ACMer,无人不知无人不晓. 在此,附上vjudge平台上一位大神整理的[kuangbin带你飞]专题目录链接. [kuangbin带你飞专题目录1-23] ...

  7. [kuangbin带你飞]专题十二 基础DP1 题解+总结

    kuangbin带你飞:点击进入新世界 总结: 简单dp,最近在做,持续更新. 文章目录 总结: 1.Max Sum Plus Plus 2.Ignatius and the Princess IV ...

  8. [kuangbin带你飞]专题五 并查集 题解+总结

    kuangbin带你飞:点击进入新世界 总结: 本人算是初学者中的初学者,欢迎交流~ 并查集的接触过的不多,大概只有普通并查集,带权并查集,种族并查集,传说中的可持续化并查集只是听说过还没有接触,不过 ...

  9. [kuangbin带你飞]专题一 做题顺序与题解 【简单搜索】

    随便说点: 博主正在刷kuangbin专题的题目,初学者,没接触过什么算法,刷题的初衷是备战蓝桥杯,后来发现了算法资料大多是针对acm的,挑选kuangbin专题入门也是如此,毕竟这样分类看起来比较有 ...

  10. [kuangbin带你飞]专题四 做题顺序与题解 【最短路练习】

    随便说点: 博主正在刷kuangbin专题的题目,初学者,没接触过什么算法,刷题的初衷是备战蓝桥杯,后来发现了算法资料大多是针对acm的,挑选kuangbin专题入门也是如此,毕竟这样分类看起来能达到 ...

最新文章

  1. 2D图像转3D仅需5秒,特斯拉的自动驾驶技术有救了?
  2. gitlab自带的Nginx与原Nginx冲突的解决方案
  3. SpringMVC源码分析(8)剖析ViewResolver
  4. Oracle 11g 卸载
  5. 计算机二级考试常用代码,二级计算机VB考试常用代码(看完必过).doc
  6. 数据中心机房供电需求有哪些?存在哪些电能质量问题?
  7. ALV标准范例Demo汇总
  8. android设置提交的隐藏域以及在onItemClick中获取对应的数据
  9. IPython快捷键及命令
  10. 使用hotnode自动更新脚本(热发布)
  11. z-index的学习整理转述
  12. python连接sql数据库_python连接sql server数据库实现增删改查
  13. ORACLE 12C 插入数据遇到 Error getting generated key or setting result to parameter object错误
  14. 程序员面试金典——3.7猫狗收养所
  15. 前端开发中使用build.js完成区分环境的打包配置
  16. go mysql driver事务,Go 数据库事务的源码分析
  17. java 412_http 412问题
  18. 在游戏中,爆出神装是真随机还是假随机?
  19. 腾冲樱花谷原生态旅游景区公园网站制作完成
  20. html5一阶段考试题,千锋HTML5-JS阶段第三周理论考试题目02

热门文章

  1. 各主流浏览器的JS执行能力测试
  2. 有关分组、帧、报文、比特流的问题
  3. bim webgl 模型 轻量化_BIM模型轻量化是什么?BIM模型轻量化原理
  4. 有关C++的标准模板库(STL)的一些个人易错点
  5. 电脑更新重启后黑屏_电脑黑屏重启还是黑屏的解决方法教程
  6. 3d slicer调整窗宽窗位_3D游戏模型制作技巧,掌握这些技术你也能进鹅厂!
  7. #Pragma Pack(n)与内存分配
  8. unix编程实训教程之 more(觉醒篇一 Begin)
  9. 山大网络计算机基础知识模拟,山大网络教育计算机系统结构模拟试卷1
  10. 【算法笔记】图文结合彻底搞懂后缀数组