标签:Paths tarjan 洛谷 int 割边 tot dfn low
本题的大意就是加最少的边使得图成为边双。
多举例子,画图分析可得:最终答案就是叶子节点(度数为1的点)的个数加1在除以2。
那么我们的目的就转化为找叶子节点:
首先通过tarjan找到割边,再dfs将原图分为几个边双(通过割边划分),缩点,最后统计度数为1的节点个数即可。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=100100; 4 int n,m,ans,tot=1,cnt,sum; 5 int dfn[N],low[N]; 6 int head[N],to[N],nxt[N]; 7 int num[N],du[N],way[N];//way[]用来统计割边 8 9 void add(int u,int v){//tot从2开始,方便通过异或找反向边 10 nxt[++tot]=head[u]; 11 head[u]=tot; 12 to[tot]=v; 13 } 14 15 void tarjan(int u,int fa){//fa是u的父亲边,该函数目的是为了找割边,不需要栈 16 low[u]=dfn[u]=++cnt; 17 for(int i=head[u];i;i=nxt[i]){ 18 int v=to[i]; 19 if(!dfn[v]){ 20 tarjan(v,i); 21 low[u]=min(low[u],low[v]); 22 if(low[v]>dfn[u]) way[i]=way[i^1]=1;//i及其反向边是割边 23 } 24 else if(fa!=(i^1)) low[u]=min(low[u],dfn[v]); 25 } 26 } 27 28 void dfs(int u){ 29 num[u]=sum; 30 for(int i=head[u];i;i=nxt[i]){ 31 if(way[i]||num[to[i]]) continue;//u是割边或者对面点已经属于另外的连通块 32 dfs(to[i]); 33 } 34 } 35 36 int main(){ 37 scanf("%d%d",&n,&m); 38 while(m--){ 39 int x,y; 40 scanf("%d%d",&x,&y); 41 add(x,y);add(y,x); 42 } 43 tarjan(1,0);//0是1的父亲边 44 for(int i=1;i<=n;i++) 45 if(!num[i]) {sum++;dfs(i);}//sum统计连通块的个数 46 for(int i=1;i<=n;i++) 47 for(int j=head[i];j;j=nxt[j]) 48 if(num[i]!=num[to[j]]) du[num[to[j]]]++; 49 for(int i=1;i<=sum;i++) 50 if(du[i]==1) ans++; //求度数为1的叶子节点 51 cout<<(ans+1)/2<<endl; 52 return 0; 53 }
标签:Paths,tarjan,洛谷,int,割边,tot,dfn,low 来源: https://www.cnblogs.com/yhxnoerror/p/16364781.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。