Ural 1557 1557. Network Attack

原创 2015年07月10日 17:06:11

题目链接:http://acm.timus.ru/problem.aspx?space=1&num=1557 


题目大意:给一个N个点M条边的无向连通图,求所有删除两条边使得图不连通的方案数。

数据范围:1<= N <= 2000 , 0 <= M <= 100000


两种情况:

第一: 有一条边是桥,其他任意删一条边,就可使得图不连通

第二: 两条边都不是桥,删除这两条边使得图不连通。


使用DFS搜索出所有的桥便可算出第一类;

第二类,同样是使用DFS,生成DFS树,由于DFS树没有横向边,所以我们只需要考虑子节点和父节点的关系。

首先,对于节点u,假如 u 和 u 的所有子数里面的点只有两条边可以访问到u的祖先节点,那么u边可以贡献一个答案。

还有,若 u 和其父亲只有一条连边,则扫描u的子数中所有节点,不包括u的节点j,假如j满足以下条件:

(1): j 与其父亲只有一条连边

(2):j 以及j的子树 可以访问到的j的祖先的边  和  u及u的子树可以访问到的u的祖先的边  相等

(3):j 可以用回边访问到的最近的祖先(即除了其直接父亲过来的边以外,能访问到的最近的祖先节点) 要  在u上面  (即深度小于u的深度)

满足这三个条件,对答案贡献 1 。

当满足这三个条件是,就是下图中画上红色的这种情况:


在u的子树种,找到所有满足这种情况的即可。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 2005;
struct Edge
{
    int from,to;
};
vector<Edge>E;
vector<int>G[maxn];
int bridge,nobridge;
int dep[maxn];
int low_set[maxn][maxn];
int s[maxn],t[maxn];
bool check(int x,int fa)
{
    int res = 0;
    for(int i=0;i<G[fa].size();i++)
        if( E[ G[fa][i] ].to == x ) res++;
    return res == 1;
}
bool vis[maxn];
void dfs2(int x,int tx,int sx)
{
    for(int i=0;i<G[x].size();i++)
    {
        int to = E[ G[x][i] ].to;
        if(dep[to] != dep[ x ]+1) continue;
        if(vis[to]) continue; // 防止重边进入子树多次
        vis[to] = 1;
        if( check(to,x) && t[to] < tx && s[to] == sx )
            nobridge++;
        dfs2(to,tx,sx);
    }
}
void dfs(int x, int fa, int deep,int NE)
{
    dep[x] = deep;
    if(fa == -1) s[x] = 0;
    else s[x] = 1;
    t[x] = 1;
    for(int i=0;i<G[x].size();i++)
    if( (G[x][i] ^ 1) != NE )
    {
        int to = E[ G[x][i] ].to;
        if( !dep[to] ){
            dfs(to,x,deep+1,G[x][i]);
            for(int j=1; j<=deep; j++)
            {
                if( low_set[ to ][ j ] )
                {
                    low_set[x][j] += low_set[ to ][j];
                }
            }
        }
        else if( dep[to] < dep[x] )
        {
            low_set[ x ][ dep[ to ] ] ++ ;
        }
    }
    for(int i=1;i<deep;i++)
    {
        if(low_set[x][i]){
            s[x] += low_set[x][i];
            t[x] = i;
        }
    }
    if(s[x] == 1) bridge++;
    else if(s[x] == 2) nobridge++;
    if( s[x] != 1 && check(x,fa)  )
    {
        memset(vis,0,sizeof(vis));
        dfs2(x,dep[x],s[x]);
    }
}
void Add_Edge(int from,int to)
{
    E.push_back( (Edge){from,to} );
    E.push_back( (Edge){to,from} );
    int m = E.size();
    G[from].push_back(m-2);
    G[to].push_back(m-1);
}
int n,m,u,v;
void init()
{
    memset(dep,0,sizeof(dep));
    memset(low_set,0,sizeof(low_set));
    for(int i=1;i<=n;i++) G[i].clear();
    E.clear();
    bridge = nobridge = 0;
    memset(vis,0,sizeof(vis));
}
int main()
{
    while(~scanf("%d%d",&n,&m)){
        init();
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&u,&v);
            Add_Edge(u,v);
        }
        dfs(1,-1,1,-1);
        int ans = bridge*(m-bridge) + bridge*(bridge-1)/2;
        cout<<ans+nobridge<<endl;
    }
    return 0;
}
/*
5 7
4 5
1 2
2 3
3 4
3 4
3 4
1 5
6
*/


版权声明:本文为博主原创文章,未经博主允许不得转载。

Timus 1557 Network Attack DFS+各种各种...

感觉比较复杂的一个题目 开始写的时候漏掉了一种情况之后就开始卖萌不止。。。 拖了好久才过;比较考验思维严谨性的题目。 题目的含义是给出一个N(不大于2000)个点 M(不大于100000)条边 的图...

Visual Assist X 10.3.1557.0 VA_X_Setup1557

  • 2007年06月25日 17:37
  • 3.58MB
  • 下载

<C/C++算法>九度OJ题目1516--1557解题练习(十)

题目描述: 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。...

[SPOJ1557][GSS2][线段树]Can you answer these queries II[好题]

[SPOJ1557][GSS2][线段树]Can you answer these queries II[好题]

南邮 OJ 1557 Tower Parking

Tower Parking 时间限制(普通/Java) : 1000 MS/ 3000 MS          运行内存限制 : 65536 KByte 总提交 : 11           ...

HDU 1557 权利指数 状态压缩 暴力

HDU 1557 权利指数 状态压缩 暴力 ACM 题目地址:HDU 1557 权利指数 题意:  中文题,不解释。 分析:  枚举所有集合,计算集合中的和,判断集合里面的...
  • hcbbt
  • hcbbt
  • 2014年06月28日 15:35
  • 1361

[codevs1557/tyvj1031/USACO OTC09 9TH]热浪[tyvj3187]最小花费 图论算法之dijkstra 学习笔记

图论算法之Dijkstra 【算法思路】 s[i]表示起点到i的最短路径的值; 初始时s[起点]赋为0,其余正无穷; 每一次找到一个s[i]最小的点minj,置标记,然后把所有没有标记过的且与点min...

【SPOJ】1557 Can you answer these queries II 线段树

传送门:【SPOJ】1557 Can you answer these queries II

51nod 1557 两个集合

开2倍n的并查集。其中,i所在的并查集与i+n所在的并查集,分别表示与数字p[i]所在的集合,以及数字p[i]所不在的集合。 也就是说,在正常情况下,i所在的并查集与i+n所在的并查集,不是同一个并...
  • xin_jun
  • xin_jun
  • 2017年06月17日 22:26
  • 76
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Ural 1557 1557. Network Attack
举报原因:
原因补充:

(最多只允许输入30个字)