洛谷P3388割点题解

1. 本题其实就是一道基础的模板题
2.算法思想主要考察割点
1. ```cpp
int child = 0;

t++;
num[cur] = t;
low[cur] = t;
book[cur] = true;
for(int i = first[cur];i != -1;i = next[i])
{
book[v[i]] = true;
if(num[v[i]] == 0)
{
child++;
dfs(v[i],cur);

low[cur] = min(low[cur],low[v[i]]);

if(cur != root && low[v[i]] >= num[cur])
flag[cur] = 1;
if(cur == root && child == 2)
flag[cur] = 1;
}
else if(v[i] != father)
low[cur] = min(low[cur],num[v[i]]);
}
```
此为核心代码
有以下几点注意事项
1. low数组表示该点不通过父节点能到达的最远最上的结点,num表示该点的时间戳
2.当该点的low大于等于该点的父节点的num时,该父节点就将该点与原集合分开了
那么该父节点也就是一个割点//重要算法思想
3.root的定义是dfs开始时的根结点,cur表示正在查询的子结点,father表示父节点
4.当cur=root我们只需要判断cur点有无两个子节点就好了,如果有则说明该根节点是一个割点
5.book数组表示该点是否已经被判断,在主函数中方便判断是否应该进行深搜
如下```
for(int i = 1;i <= n;i++)
{
if(!book[i])
{
root = i;//混账!!!!! 
book[i] = true;
dfs(i,i);
}
}
```
6.在解决输入时候如果我们直接用二维数组存图是十分方便的,但是n*n的空间复杂度显然不能成为好的解法,所以这里我们需要借用领接表进行存图
如下
```
for(int i = 1;i <= m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
//邻接表 
u[++cnt] = x,v[cnt] = y;
next[cnt] = first[u[cnt]];
first[u[cnt]] = cnt;
u[++cnt] = y,v[cnt] = x;
next[cnt] = first[u[cnt]];
first[u[cnt]] = cnt;
}
```
m表示一共有多少组数据,
这里有点很重要。first next 必须初始化为-1,否则在后面dfs当中将会无法处理边界问题

7.在定义数组大小时,我们需要在原来n的规模上乘2,因为该通道是无向的,并且在领接表的处理中需要双向处理

附上AC代码
```
#include <cstdio> 
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#define maxn 100010

using namespace std;

int first[2*maxn],next[2*maxn],cnt,ans;
int n,m,u[2*maxn],v[2*maxn],t;
int root = 1,flag[maxn],num[maxn],low[maxn];
bool book[20005];
void dfs(int cur,int father)
{
int child = 0;
t++;
num[cur] = t;
low[cur] = t;
book[cur] = true;
for(int i = first[cur];i != -1;i = next[i])
{
book[v[i]] = true;
if(num[v[i]] == 0)
{
child++;
dfs(v[i],cur);
low[cur] = min(low[cur],low[v[i]]);
if(cur != root && low[v[i]] >= num[cur])
flag[cur] = 1;
if(cur == root && child == 2)
flag[cur] = 1;
}
else if(v[i] != father)
low[cur] = min(low[cur],num[v[i]]);
}
return;
}
int main()
{

scanf("%d%d",&n,&m);
memset(first,-1,sizeof(first));
memset(next,-1,sizeof(next));
for(int i = 1;i <= m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
//邻接表 
u[++cnt] = x,v[cnt] = y;
next[cnt] = first[u[cnt]];
first[u[cnt]] = cnt;
u[++cnt] = y,v[cnt] = x;
next[cnt] = first[u[cnt]];
first[u[cnt]] = cnt;
}
for(int i = 1;i <= n;i++)
{
if(!book[i])
{
root = i;//混账!!!!! 
book[i] = true;
dfs(i,i);
}
}
// if(flag[2]==true)
// flag[2] = false;
for(int i = 1;i <= n;i++)
if(flag[i])
ans++;
printf("%d\n",ans);
for(int i = 1;i <= n;i++)
if(flag[i] == 1)
printf("%d ",i);

return 0;
}
```

猜你喜欢

转载自www.cnblogs.com/my-Sabrina/p/11070703.html