图论(无向图的割顶):POJ 1144 Network

Network

Description

  A Telephone Line Company (TLC) is establishing a new telephone cable network. They are connecting several places numbered by integers from 1 to N . No two places have the same number. The lines are bidirectional and always connect together two places and in each place the lines end in a telephone exchange. There is one telephone exchange in each place. From each place it is possible to reach through lines every other place, however it need not be a direct connection, it can go through several exchanges. From time to time the power supply fails at a place and then the exchange does not operate. The officials from TLC realized that in such a case it can happen that besides the fact that the place with the failure is unreachable, this can also cause that some other places cannot connect to each other. In such a case we will say the place (where the failure occured) is critical. Now the officials are trying to write a program for finding the number of all such critical places. Help them.

Input

  The input file consists of several blocks of lines. Each block describes one network. In the first line of each block there is the number of places N < 100. Each of the next at most N lines contains the number of a place followed by the numbers of some places to which there is a direct line from this place. These at most N lines completely describe the network, i.e., each direct connection of two places in the network is contained at least in one row. All numbers in one line are separated
by one space. Each block ends with a line containing just 0. The last block has only one line with N = 0;

Output

  The output contains for each block except the last in the input file one line containing the number of critical places.

Sample Input

  5
  5 1 2 3 4
  0
  6
  2 1 3
  5 4 6 2
  0
  0

Sample Output

  1
  2

Hint

  You need to determine the end of one line.In order to make it‘s easy to determine,there are no extra blank before the end of each line.

  这道题就是求无向图的割顶,一般用tarjan算法。

  刘汝佳老师的书上有写,还注明要注意一些地方,被称为"写错",可我觉得有些地方没注意只是不严谨,并不影响正确性。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int maxn=100010;
int n,fa[maxn],ch[maxn][2],sz[maxn];
int flip[maxn],pos[maxn],rt;
struct Node{
    int x,id;
}a[maxn];

void Flip(int x){
    swap(ch[x][0],ch[x][1]);
    flip[x]^=1;
}

void Push_down(int x){
    if(flip[x]){
        Flip(ch[x][0]);
        Flip(ch[x][1]);
        flip[x]=0;
    }
}

int pd[maxn];
void P(int x){
    int cnt=0;
    while(x){
        pd[++cnt]=x;
        x=fa[x];
    }
    while(cnt){
        Push_down(pd[cnt--]);
    }
}

void Push_up(int x){
    sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+1;
}

void Rotate(int x){
    int y=fa[x],g=fa[y],c=ch[y][1]==x;
    ch[y][c]=ch[x][c^1];fa[ch[x][c^1]]=y;
    ch[x][c^1]=y;fa[y]=x;fa[x]=g;
    if(g)ch[g][ch[g][1]==y]=x;
    Push_up(y);
}

void Splay(int x,int g=0){
    P(x);
    for(int y;(y=fa[x])!=g;Rotate(x))
        if(fa[y]!=g)
            Rotate((ch[fa[y]][1]==y)==(ch[y][1]==x)?y:x);
    Push_up(x);
    if(!g)rt=x;
}

int Build(int f,int l,int r){
    if(l>r)return 0;
    int mid=(l+r)>>1;fa[mid]=f;
    ch[mid][0]=Build(mid,l,mid-1);
    ch[mid][1]=Build(mid,mid+1,r);
    sz[mid]=1;
    Push_up(mid);
    return mid;
}

bool cmp(Node a,Node b){
    if(a.x!=b.x)
    return a.x<b.x;
    return a.id<b.id;
}

int main(){
    while(~scanf("%d",&n)&&n){
        memset(flip,0,sizeof(flip));
        rt=Build(0,1,n+2);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i].x);
        for(int i=1;i<=n;i++)
            a[i].id=i;
        sort(a+1,a+n+1,cmp);
        for(int i=1;i<=n;i++)
            pos[i+1]=a[i].id+1;
        pos[1]=1;pos[n+2]=n+2;
        for(int i=2,p;i<n+1;i++){
            Splay(pos[1]);
            Splay(pos[i],pos[1]);
            printf("%d ",sz[ch[ch[rt][1]][0]]+1);
            Splay(pos[i]);
            p=ch[pos[i]][1];
            while(ch[p][0]){
                Push_down(p);
                p=ch[p][0];
            }
            Push_down(p);
            Splay(pos[i-1]);
            Splay(p,pos[i-1]);
            Flip(ch[ch[rt][1]][0]);
        }
        printf("%d\n",n);
    }
    return 0;
}
时间: 2024-10-14 18:12:47

图论(无向图的割顶):POJ 1144 Network的相关文章

求无向图的割点 (poj 1144 Network)

割点 :去掉该点后原来的图不连通(出现好几个连通分量),该点被称为割点. 注意删除某点意味着和该点关联的边也全部删除 求割点的伪代码 DFS(v1,father): dfn[v1] = low[v1] = ++dfsClock vis[v1] = true child = 0 for each egde(v1,v2) in E: if(vis[v2] == false) : //(v1,v2)是父子边 DFS(v2,v1) child++ low[v1] = Min(low[v1],low[v2

无向图求割顶与桥

无向图求割顶与桥 对于无向图G,如果删除某个点u后,连通分量数目增加,称u为图的关节点或割顶.对于连通图,割顶就是删除之后使图不再连通的点.如果删除边(u,v)一条边,就可以让连通图变成不连通的,那么边(u,v)是桥. 具体的概念和定义比较多,在刘汝佳<<训练指南>>P312-314页都有详细的介绍. 下面来写求无向图割顶和桥的DFS函数.我们令pre[i]表示第一次访问i点的时间戳,令low[i]表示i节点及其后代所能连回(通过反向边)的最早祖先的pre值. 下面的dfs函数返回

【模板】无向图的割顶

无向图的割顶: Vector <int> G[] :邻接表存图 Int pre[] :存储时间戳 Int low[] : u及其后代所能连回的最早的祖先的pre值 Int iscut[] : =true表示是割顶,=false不是割顶 Dfs函数在主函数调用时,fa预设为-1. vector <int> G[MAXN]; int pre[MAXN],iscut[MAXN],low[MAXN],dfs_clock; int dfs(int u,int fa) { int lowu=p

连通分量 无向图的割顶和桥 无向图的双连通分量 有向图的强连通分量

时间戳 dfs_clock :说白了就是记录下访问每个结点的次序.假设我们用 pre 保存,那么如果 pre[u] > pre[v], 那么就可以知道先访问的 v ,后访问的 u . 现在给定一条边, (u, v), 且 u 的祖先为 fa, 如果有 pre[v] < pre[u] && v != fa, 那么 (u, v) 为一条反向边. 1 求连通分量: 相互可达的节点称为一个连通分量: #include <iostream> #include <cstd

POJ 1144 Network【割顶】

学习的这一篇:https://www.byvoid.com/blog/biconnect 割顶:对于无向图G,如果删除某个点u后,连通分量数目增加,称u为图的关节点或者割顶 u为割顶的条件: (1)u不为树根,以u的任一子节点为根的子树中没有一个点有返回u的祖先的反向边(返祖边) (2)u为树根,且u有多于一个子树 紫书上有证明 即为,祖先与每一棵子树之间都有返祖边的话(即,删除u点之后,以v为根的整棵子树都可以通过这条返祖边连回到f),该点不是割顶,如果祖先与它的其中一棵子树缺少返祖边的话,那

无向图的割顶(poj1523,1144)

割顶:表示无向图中的点,这个点删除之后,原图不在联通,这样的点就是割顶. 怎么求一个图中的割顶呢? 把无向图变成一颗树,dfs时候搜索到在dfs树上的称为树边,搜索是出现后代指向祖先的边称为反向边. 对于根节点,当他存在两个或两个以上的子节点时,那么他就是割顶. 而对于其他节点u,当且仅当u存在一个子节点v,使得v及其所有的后代都没有反向边连回u的祖先时,u是一个割顶. 那么判断就很简单,这里给出两个模板: 题目:poj1523 和 1144都是裸的求割顶的题目 通用模板: #include <

UVA 315 :Network (无向图求割顶)

题目链接 题意:求所给无向图中一共有多少个割顶 用的lrj训练指南P314的模板 #include<bits/stdc++.h> using namespace std; typedef long long LL; const int N=109; struct Edge { int to,next; Edge(){} Edge(int _to,int _next) { to=_to; next=_next; } }edge[N*N*2]; int head[N]; int dfn[N],lo

POJ 1144 Network(无向图连通分量求割点)

题目地址:POJ 1144 求割点.推断一个点是否是割点有两种推断情况: 假设u为割点,当且仅当满足以下的1条 1.假设u为树根,那么u必须有多于1棵子树 2.假设u不为树根.那么(u,v)为树枝边.当Low[v]>=DFN[u]时. 然后依据这两句来找割点就能够了. 代码例如以下: #include <iostream> #include <cstdio> #include <string> #include <cstring> #include &

无向图的割顶和桥

割顶: 关键点,删掉这个点后,图的连通分量 + 1: 桥: 在割顶的基础上,发现删除 (u,v) 这条边,图就变成非连通的了. 如何找出所有割顶和桥: 时间戳: 在无向图的基础上,DFS建树的过程中,各点进栈和出栈的时间 dfs_clock,进栈的时间 pre[],出栈的时间 post[] 在DFS程序中的体现就是: void previst(int u) { pre[u]= ++dfs_clock; } void postvist(int u) { post[u] = ++dfs_clock;