2013 ACM/ICPC南京邀请赛B题(求割点扩展)
题目链接:http://icpc.njust.edu.cn/Contest/194/Problem/B
B - TWO NODES
时间限制: | 10000 MS |
内存限制: | 65535 KB |
问题描述
Suppose that G is an undirected graph, and the value of stab is defined as follows:
Among the expression, G-i,-j is the remainder after removing node i, node j and all edges that are directly relevant to the previous two nodes.cntCompent(X) is the number of connected components of X independently.
Thus, given a certain undirected graph G, you are supposed to calculating the value of stab .
输入说明
Input consists of multiple cases.
The input will contain the description of several graphs. For each graph, the description consist of an integer N for the number of nodes, an integer M for the number of edges, and M pairs of integers for edges (3<=N,M<=5000).
Please note that the endpoints of edge is marked in the range of [0,N-1], and input cases ends with EOF.
输出说明
For each graph in the input, you should output the value of stab.
输入样例
4 5 0 1 1 2 2 3 3 0 0 2
输出样例
2
南京邀请赛的B题。。。。
一道饮恨的题目,那个时候太弱了,n=5000,复杂度为O(n^2)的算法不敢去搞了,时限竟然有10s
那个时候对求割点不熟悉。
最近搞了下连通图,弄了下割点和桥的求法。
然后写了下这题,写完1A了。
这题就是去掉两个点,问可以最多留下多少个连通分支。(现场比赛有提问说了,去掉的是两个不同的点)
枚举第一个去掉的点。然后就是普通的求割点的过程来实现去掉一个点可以增加多少个连通块。
然后就搞出来了
#include <stdio.h> #include <algorithm> #include <string.h> #include <iostream> using namespace std; const int MAXN = 5050; const int MAXM = 10010; struct Edge { int to,next; }edge[MAXM]; int head[MAXN],tot; int Low[MAXN],DFN[MAXN],Stack[MAXN]; int Index,top; bool Instack[MAXN]; bool cut[MAXN]; int add_block[MAXN]; void addedge(int u,int v) { edge[tot].to = v;edge[tot].next = head[u];head[u] = tot++; } int subindex; void Tarjan(int u,int pre) { int v; DFN[u] = Low[u] = ++Index; Stack[top++] = u; Instack[u] = true; int son = 0; for(int i = head[u];i != -1;i = edge[i].next) { v = edge[i].to; if(v == pre)continue; if(v == subindex)continue; if(!DFN[v]) { son++; Tarjan(v,u); if(Low[u] > Low[v])Low[u] = Low[v]; if(u != pre && Low[v] >= DFN[u]) { cut[u] = true; add_block[u]++; } } else if(Instack[v] && Low[u] > DFN[v]) Low[u] = DFN[v]; } if(u == pre && son > 1)cut[u] = true; if(u == pre )add_block[u] = son - 1; Instack[u] = false; top--; } int solve(int N) { memset(DFN,0,sizeof(DFN)); memset(Instack,false,sizeof(Instack)); memset(add_block,0,sizeof(add_block)); memset(cut,false,sizeof(cut)); Index = top = 0; int cnt = 0; int ans = 0; for(int i = 0;i < N;i++) if(i != subindex &&!DFN[i]) { Tarjan(i,i); cnt++; } for(int i = 0;i < N;i++) if(i != subindex) ans = max(ans,cnt + add_block[i]); return ans; } void init() { tot = 0; memset(head,-1,sizeof(head)); } int main() { int n,m; while(scanf("%d%d",&n,&m)==2) { init(); int u,v; while(m--) { scanf("%d%d",&u,&v); addedge(u,v); addedge(v,u); } int ans = 0; for(int i = 0;i < n;i++) { subindex = i; ans = max(ans,solve(n)); } printf("%d\n",ans); } return 0; }