Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 10257 | Accepted: 4418 |
Description
Input
Output
Sample Input
7 7 1 2 2 3 3 4 2 5 4 5 5 6 5 7
Sample Output
2题意:问你在图中加几条边使每个点到其他点的路径数不小于2条。
分析:由于图是无向图,所以在一个连通分量中的每个点到其他点的路径至少是2条的,然后就考虑每个连通分量与多少个连通分量相连,如果只和一个相连,那么他就必须要连出一条边。
本题有重边,所以直接按照双连通分量的方法可能会把不在同一分量的加在同一分量中,然而并不想用一个二维数组标记(浪费时间,浪费空间),所以把桥标记为1,重复的桥标记为2。
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<string> #include<vector> #include<queue> #include<cmath> #include<stack> #include<set> #include<map> #define INF 0x3f3f3f3f #define MAX 10005 #define mod 10000007 #define CLR(a,b) memset((a),(b),sizeof((a))) #pragma comment(linker, "/STACK:102400000,102400000") #define ul u<<1 #define ur (u<<1)|1 using namespace std; typedef long long ll; struct edge { int v,next; } e[MAX*2]; int tot,head[MAX]; int dfs_clock,bcc_cnt,pre[MAX],low[MAX],bridge[MAX*2],vis[MAX]; void addedge(int u,int v) { e[tot].v=v; e[tot].next=head[u];; head[u]=tot++; } void tdfs(int u,int fa) { pre[u]=low[u]=++dfs_clock; for(int i=head[u]; i!=-1; i=e[i].next) { int v=e[i].v; if(!pre[v]) { tdfs(v,u); low[u]=min(low[u],low[v]); if(low[v]>pre[u]) bridge[i]=bridge[i^1]=1; ///标记桥 } else { if(pre[v]<pre[u]&&v!=fa) low[u]=min(low[u],pre[v]); if(low[v]>pre[u]) bridge[i]=bridge[i^1]=2; ///标记重复的桥 } } } int e_cnt; void dfs(int u) { vis[u]=1; for(int i=head[u]; i!=-1; i=e[i].next) { if(bridge[i]) { if(bridge[i]==1) ///记录该双连通分量的桥 e_cnt++; continue; } int v=e[i].v; if(!vis[v]) { dfs(v); } } } void find_bcc(int n) { CLR(pre,0); CLR(low,0); CLR(bridge,0); dfs_clock=0; for(int i=1; i<=n; i++) if(!pre[i]) tdfs(i,i); } void init() { tot=0; CLR(head,-1); } int main() { int n,m,u,v; init(); scanf("%d%d",&n,&m); for(int i=1; i<=m; i++) { scanf("%d%d",&u,&v); addedge(u,v); addedge(v,u); } find_bcc(n); int num=0; for(int i=1; i<=n; i++) { e_cnt=0; if(!vis[i]) { dfs(i); if(e_cnt==1) num++; ///桥为1时说明只有一条路到其他连通分量 } } printf("%d\n",(num+1)/2); return 0; }