hdu3671 Boonie and Clyde (Tarjan求割点)
2015-10-12 16:37
274 查看
http://acm.hdu.edu.cn/showproblem.php?pid=3671
题目大意:给定连通无向图,求可行的点对的数量,该点对可以使图在删去该点对后剩下的图中,至少有一对点不连通。
Tarjan算法求强连通图的复杂度是O(n),如果直接枚举两个点并且求连通的话,总的复杂度为O(n^3)
如果先删去一个点,如果剩下的图分成了二个以上的块,则认为只要删去了这个点,剩下n-1个点无论删去哪个都是有效答案。因此对答案贡献为n-1
如果分成了两个块,则要分情况讨论。如果有一块只有一个点,则删去这个点后,原来两个块又变成了一个块,此时这种情况对答案的贡献是n-2。如果两个块都只有一个点,则这个图在删点前就只有3个点,是无解的。
如果分成一个块,则按照正常的Tarjan求割点流程求割点数量即可。
因为每一对点都有重复统计一次,最后答案要除以2
Tarjan求割点流程:
在遍历树中,如果一个非根节点u的子节点v,有DFN[v]<=LOW[u],证明该子节点不能通过一个回边回到节点u的上层。此时该节点u即为割点。
对于根节点,若它的子树数量>1,则它也是割点。
题目大意:给定连通无向图,求可行的点对的数量,该点对可以使图在删去该点对后剩下的图中,至少有一对点不连通。
Tarjan算法求强连通图的复杂度是O(n),如果直接枚举两个点并且求连通的话,总的复杂度为O(n^3)
如果先删去一个点,如果剩下的图分成了二个以上的块,则认为只要删去了这个点,剩下n-1个点无论删去哪个都是有效答案。因此对答案贡献为n-1
如果分成了两个块,则要分情况讨论。如果有一块只有一个点,则删去这个点后,原来两个块又变成了一个块,此时这种情况对答案的贡献是n-2。如果两个块都只有一个点,则这个图在删点前就只有3个点,是无解的。
如果分成一个块,则按照正常的Tarjan求割点流程求割点数量即可。
因为每一对点都有重复统计一次,最后答案要除以2
Tarjan求割点流程:
在遍历树中,如果一个非根节点u的子节点v,有DFN[v]<=LOW[u],证明该子节点不能通过一个回边回到节点u的上层。此时该节点u即为割点。
对于根节点,若它的子树数量>1,则它也是割点。
#pragma comment(linker, "/STACK:102400000,102400000") #include<iostream> #include<iomanip> #include<cstdio> #include<cstring> #include<sstream> #include<stack> #include<queue> #include<fstream> #include<algorithm> #include<map> #include<set> #include<vector> #include<functional> #include<cmath> #define CLR(x) memset(x,0,sizeof(x)) #define SETMAX(x) memset(x,0x3f,sizeof(x)) #define SETNO(x) memset(x,-1,sizeof(x)) #define ll long long #define eps 3e-12 #define pow2(x) ((x)*(x)) #define forto(i,n) for(int i=0;i<n;i++) #define for1to(i,n) for(int i=1;i<=n;i++) #define VI vector<int> using namespace std; const double PI=acos(-1.0); #define INF 0x3f3f3f3f #define NINF 0xbfffffff int p[1111]; int to[21111]; int bro[21111]; int tot; void addEdge(int a,int b) { to[++tot]=b; bro[tot]=p[a]; p[a]=tot; } int rem; int index; int DFN[1111]; int LOW[1111]; int root; int ans; int tarjan(int s) { DFN[s]=LOW[s]=++index; int sons=0; int tp=1; for(int t=p[s];t;t=bro[t]) { int tar=to[t]; if (rem==tar) continue; if (!DFN[tar]) { sons++; tp+=tarjan(tar); LOW[s]=min(LOW[s],LOW[tar]); if (s!=root&&DFN[s]<=LOW[tar]) ans++; } else LOW[s]=min(LOW[s],DFN[tar]); } if (s==root&&sons>1) ans++; return tp; } int main() { ios_base::sync_with_stdio(false); #ifndef ONLINE_JUDGE //freopen("test.txt","r",stdin); #endif // ONLINE_JUDGE int n,m; int C=1; while(scanf("%d%d",&n,&m),n||m) { CLR(p); tot=0; forto(i,m) { int a,b; scanf("%d%d",&a,&b); addEdge(a,b); addEdge(b,a); } int result=0; for(int i=1;i<=n;i++) { int res[1111]; int resp=0; CLR(DFN); index=1; rem=i; ans=0; for(int j=1;j<=n;j++) if (j!=rem&&!DFN[j]) { root=j; res[resp++]=tarjan(j); } if (resp>=3) { result+=n-1; } if (resp==2) { result+=n-1; if (res[0]==1) result--; if (res[1]==1) result--; } if (resp==1) result+=ans; } printf("Case %d: %d\n",C++,result/2); } return 0; }
相关文章推荐
- Struts2 多文件上传
- 阿里旺旺前辈告诉我们。。。
- Win10使用中的一些问题
- unsupported major.minor version 解决方法
- 虚拟机VMware无法识别USB设备
- zoj3905 Cake
- 第三周。项目4--顺序表应用(2)
- 项目4 -- 链表算法库 程序的多文件组织形式
- 第六周 1,建立链队算法库
- YTKNetwork 使用基础教程
- Android的IPC机制Binder的详解汇总
- 软件测试管理要素
- 欢迎使用CSDN-markdown编辑器
- python udp编程实例
- 能挣钱的微信JSSDK+H5混合开发
- 大数据SPSS分析-均值比较和T检验
- 第七周项目三~~负数把正数赶出队列
- ContextLoaderListener(监听器)
- [回顾] 如何在Nexus 5(Android 4.4.4)上开启交换分区swap
- 第四周项目 - 建设“单链表”算法库