SGU 525Revolutionary Roads (Tarjan+Dfs)
来源:互联网 发布:淘宝买高压气瓶犯法吗 编辑:程序博客网 时间:2024/06/10 16:07
题意:
给你一个有向图,可以对其中至多一条边做修改,使得它变成双向边,然后让整个图的最大强联通分量里的点最多,
问能有多少种这样的修改方案,输出方案数,然后按照输入的顺序输出满足条件的边的编号。
保证了不会有自环,保证不会有重边,n<1000,m<20000。
分析:
1.先用Tarjan缩点,然后重新建图,这时候的新图不连通。
2.然后就要找那个最大的强连通分量了,但是直接枚举边然后再算连通分量里面的点数的话会T
3.这时候就要预处理出一些数据。
用Dfs处理出每一个点可以到达哪些点,存在一个矩阵里,1表示可以连接。
这里的处理要在O(n*n)的时间里处理出来,我之前用的是O(n*m)就T了。
一般的Dfs是看边,对所有有连边的点都访问,但是这里会出现很多的重复,比如下图:
这里在Dfs里面加一个vi数组记录在这一次的Dfs里面某个点是不是已经确定被访问过了,也就是说点4如果通过road 1访问过了,就可以确定点4以及点5及其之后的点都可以确定能够被start到达,所以在Dfs到road 2的时候就不用再访问点4了,road 3也是类似,这样就可以降下来复杂度。
对每一个缩过的点进行Dfs,每一次复杂度是O(n),总的就是O(n*n)。
这里Dfs有几点注意的:
<1> 在换起点的时候要对vi数组清空,因为每一次的标记都不能相互影响,有第一次就是因为这样错的。
<2> 每一次Dfs时的起点要标记vi=1,然后访问过某个点后也要加标记
<3> 注意不要重复fa访问(但是因为缩点后不可能联通了,所以貌似没有反向边了)
<4> 还有一种记录depth的姿势,我试过WA了,可能是我写挫了 Orz。
4.然后就是枚举每一条边,如果不是在一个连通分量里面,就对他们能到的点取交集,这里可以想象一下就是好几个包含三个缩过的点的小圈圈的集合,注意起点和终点不要重复加了。这里用一个mark数组记录这条边可以使得最大的连通分量里面的点是多少。
5.然后就是记录答案了,这里有一些坑。。
<1> 可能没有边,输出0后要记得空一行,不然貌似PE了
<2> 可能有的连通分量本身就很大,所以只要把这个连通分量里面的边都输出来就好了。
<3> 可能存在几个连通分量合起来和某个连通分量本身一样大,这时候都要输出来。
<4>为了保证输出的边是按照输入顺序的,只要扫一遍边就好了,如果这条边的mark数组对应值是最大的ma那么就输出来,或者说 它为0,如果这时候它所在的联通分量本身就是最大值就直接数出来就好了。
6.单组数据的话我怕T就没有清空什么的了。以后的话还是要注意的。
总结:
(Ps其实是想吐槽自己一下的)
这一题是寒假训练的图论题,当时就一直不过,WA,PE,RE,各种错,然后弃疗了,后来过了两周吧又想A了它,但是又是一直WA,然后弃疗到了8月,因为要做图论专题,所以下决心AC了这一题,两天总算过了啊啊啊啊啊啊!!!大半夜的太爽了,直接过来写题解,话说SGU的数据真心好啊,一个一个test分开来真心好,知道一步步是怎么错的,可以慢慢改进~
滚去睡觉了,明天多校加油!
AC代码:
#include<cstdio>#include<cstring>#include<vector>#include<iostream>#include<algorithm>using namespace std;const int maxn=3000;int n,m,res=0,resnum;int DFN[maxn],LOW[maxn],Stap[maxn],Belong[maxn],Bnum[maxn];bool instack[maxn];vector<int>po[maxn],TT[maxn];int Dindex,Stop,Bcnt;int to[maxn][maxn];int mark[20005];int ans[20005];int vi[maxn];int I;struct edge{ int b,e;}E[20005];void tarjan(int i){ int j; DFN[i]=LOW[i]=++Dindex; instack[i]=true; Stap[++Stop]=i; for (int b=0;b<po[i].size();b++) { j=po[i][b]; if (!DFN[j]) { tarjan(j); if (LOW[j]<LOW[i]) LOW[i]=LOW[j]; } else if (instack[j] && DFN[j]<LOW[i]) LOW[i]=DFN[j]; } if (DFN[i]==LOW[i]) { Bcnt++; do { j=Stap[Stop--]; instack[j]=false; Belong[j]=Bcnt; Bnum[Bcnt]++; } while (j!=i); if(res<Bnum[Bcnt]) { res=Bnum[Bcnt]; resnum=Bcnt; } }}void solve(){ int i; Stop=Bcnt=Dindex=0; memset(DFN,0,sizeof(DFN)); for (i=1;i<=n;i++) if (!DFN[i]) tarjan(i);}void dfs(int start,int fa){ int k; vi[start]=1; int size=TT[start].size(); for(k=0;k<size;k++) { int v=TT[start][k]; if(v!=fa && !vi[v]) { to[I][v]=1; vi[v]=1; //from[TT[start][k]][I]=1; dfs(v,start); } } return ;}void init(){ // memset(to,0,sizeof(to)); //memset(from,0,sizeof(from)); // memset(E,0,sizeof(E)); // memset(vi,0,sizeof(vi)); // int i; // for(i=0;i<=n;i++) // TT[i].clear(); res=0; resnum=0;}int main(){ //freopen("in.txt","r",stdin); //cout<<"sss"<<endl; while(scanf("%d %d",&n,&m)!=EOF) //scanf("%d %d",&n,&m); {init(); int be,en; for(int num=1;num<=m;num++) { scanf("%d %d",&be,&en); po[be].push_back(en); E[num].b=be; E[num].e=en; } solve(); int i,j; for(i=1;i<=m;i++) { if(Belong[E[i].b]!=Belong[E[i].e]) { TT[Belong[E[i].b]].push_back(Belong[E[i].e]); } } for(I=1;I<=Bcnt;I++) { memset(vi,0,sizeof(vi)); dfs(I,-1); } int ma=res; int cnt=0; // memset(mark,0,sizeof(mark)); for(i=1;i<=m;i++) { if(Belong[E[i].b]!=Belong[E[i].e]) { cnt=Bnum[Belong[E[i].b]]+Bnum[Belong[E[i].e]];//printf("%d --> %d\n",Belong[E[i].b],Belong[E[i].e]); for(j=1;j<=Bcnt;j++) { //printf("to[Belong[E[i].b]][j]===%d from[j][Belong[E[i].e]]==%d\n",to[Belong[E[i].b]][j],from[j][Belong[E[i].e]]); if(to[Belong[E[i].b]][j]==1 && to[j][Belong[E[i].e]]==1 && j!=Belong[E[i].e]) { cnt+=Bnum[j]; //printf("Bcnt=%d cnt=%d\n",j,cnt); } } mark[i]=cnt; if(cnt>ma) { ma=cnt,cnt=0; } } //if(cnt<res) ma=0; } /*for(i=1;i<=n;i++) { printf("%d %d\n",i,Belong[i]); } for(i=1;i<=Bcnt;i++) { for(j=1;j<=Bcnt;j++) printf("%d ",to[i][j]); printf("\n"); } for(i=1;i<=Bcnt;i++) { for(j=1;j<=Bcnt;j++) printf("%d ",from[i][j]); printf("\n"); }*/ int total=0; if(ma==res) { for(j=1;j<=m;j++) { if(Belong[E[j].b]==Belong[E[j].e] && Bnum[Belong[E[j].b]]==res||mark[j]==res) ans[total++]=j; } } else { for(j=1;j<=m;j++) { if(mark[j]==ma) ans[total++]=j; } } printf("%d\n",ma); printf("%d\n",total); { if(total==0) { printf("\n"); } else { for(i=0;i<total-1;i++) { printf("%d ",ans[i]); } printf("%d\n",ans[total-1]); } } } return 0;}
- SGU 525Revolutionary Roads (Tarjan+Dfs)
- sgu 525 Revolutionary Roads
- sgu-206 Roads
- 【Tarjan边双缩点】【CEOI2000】Roads
- Shtirlits - SGU 125 dfs
- poj3411 Paid Roads---dfs
- Paid Roads(DFS)
- Paid Roads(DFS)
- poj1724 roads(dfs)
- POJ3411 Paid Roads DFS
- Paid Roads----DFS
- poj-1724-ROADS(dfs)
- nyoj120(dfs+Tarjan)
- SGU 125. Shtirlits DFS暴搜
- SGU 461 Wiki Lists dfs
- SGU 125 Shtirlits(dfs)
- SGU 125. Shtirlits(dfs)
- 最短路+tarjan codeforces567E President and Roads
- 15.1 Reverse Integer
- ZOJ 3203 Light Bulb 三分\推公式
- 如何用django开发一个简易个人Blog
- Windows下使用CodeBlock或控制台操作遇到问题
- jquery选择器之属性过滤选择器
- SGU 525Revolutionary Roads (Tarjan+Dfs)
- HDOJ 题目2306 改革春风吹满地(数学 几何)
- 安装Window Server 2003 Enterprise 64-bit R2 iso和密钥
- HDU 4908 BestCoder Sequence
- OpenCV 矩阵—图像的基本
- 解决Android SDK Manager更新/下载不了或更新/下载速度慢的方法
- 图像全参考客观评价算法比较
- tarjan系列各种连通分量总结
- Elasticsearch模块功能之-自动发现(Discovery)