【图论】Ural 1557
2015-07-10 17:21
393 查看
Ural 1557 <---原题连接
题目大意为,两个黑客攻击一个相互连通的网络。网络中有n台计算机和m条链路。每一个人可以选择一条链路进行攻击并将其截断,问在这两个人攻击完成后,能够将这个网络分割成至少两个部分的方案由多少种。
需要注意的是,两名黑客不会攻击同一条链路。这也就说明,如果网络中仅有两个节点和一条边,答案应该是0(黑客不会同时攻击这一条链路,所以没法完成任务)
数据范围:
1 ≤ N ≤ 2000;
0 ≤ M ≤ 100000;
首先,如果攻击的两条边中有一条是“桥”,那么剩下的一条边可以任意选择。因此,我们将这个图中的所有桥的数量求出,记为bridge,那么所有选择中,有桥的方案总数应该为: bridge*(m-bridge)+bridge*(bridge-1) / 2(即是一条桥和一条非桥的边组成的方案数 + 两条都是桥组成的方案数。)
接下来,我们需要找到两条非桥的边组成的所有方案。具体方法为:
对图进行一遍dfs,得到图的dfs树。
若i为dfs树中的一个节点:
我们定义 T(i) 为以i为根节点的子树种的所有点。
定义P(i)为 i 的所有祖先节点。
定义s(i)为从P(i)中的点到T(i)中的点存在的边的数量。
定义t(i)为T(i)中所有节点能够连接到的i的祖先节点中深度最大的深度。
如上图所示:其中T(3)={ 3 ,4,5 }
P(3)={ 2, 1 }
s(3)= 3
t (3)= 2
在dfs树种,回边只会连向自己的祖先,即不会存在横边的情况。
1.对任意一个节点来说,如果他的s = 1,那么可以断定它和它的父亲的连线段是桥。
2.若节点 i 的 s 值为 2 ,那么可以断定,只要将这两条边减除,就可以将 i 与 i 的祖先分开,因此答案+1。
3.若节点 i 和父亲的边不是桥,并且与父亲节点之间只有一条边,那么可以看出,i的后继中存在与i的祖先相连的边。
若在 i 的后继中找到某一个节点 j ,它与它的父亲同样只有一条边相连,
它的s值与 i 的 s 值相等
它的最深回边所到的点是 i 的祖先
那么,只要减除i与i父亲的边,以及j与j父亲的边,即可形成新的联通分支。如下图所示的橙色边:
将有桥的方案和无桥的方案相加,即可得出总方案数。
题目大意为,两个黑客攻击一个相互连通的网络。网络中有n台计算机和m条链路。每一个人可以选择一条链路进行攻击并将其截断,问在这两个人攻击完成后,能够将这个网络分割成至少两个部分的方案由多少种。
需要注意的是,两名黑客不会攻击同一条链路。这也就说明,如果网络中仅有两个节点和一条边,答案应该是0(黑客不会同时攻击这一条链路,所以没法完成任务)
数据范围:
1 ≤ N ≤ 2000;
0 ≤ M ≤ 100000;
首先,如果攻击的两条边中有一条是“桥”,那么剩下的一条边可以任意选择。因此,我们将这个图中的所有桥的数量求出,记为bridge,那么所有选择中,有桥的方案总数应该为: bridge*(m-bridge)+bridge*(bridge-1) / 2(即是一条桥和一条非桥的边组成的方案数 + 两条都是桥组成的方案数。)
接下来,我们需要找到两条非桥的边组成的所有方案。具体方法为:
对图进行一遍dfs,得到图的dfs树。
若i为dfs树中的一个节点:
我们定义 T(i) 为以i为根节点的子树种的所有点。
定义P(i)为 i 的所有祖先节点。
定义s(i)为从P(i)中的点到T(i)中的点存在的边的数量。
定义t(i)为T(i)中所有节点能够连接到的i的祖先节点中深度最大的深度。
如上图所示:其中T(3)={ 3 ,4,5 }
P(3)={ 2, 1 }
s(3)= 3
t (3)= 2
在dfs树种,回边只会连向自己的祖先,即不会存在横边的情况。
1.对任意一个节点来说,如果他的s = 1,那么可以断定它和它的父亲的连线段是桥。
2.若节点 i 的 s 值为 2 ,那么可以断定,只要将这两条边减除,就可以将 i 与 i 的祖先分开,因此答案+1。
3.若节点 i 和父亲的边不是桥,并且与父亲节点之间只有一条边,那么可以看出,i的后继中存在与i的祖先相连的边。
若在 i 的后继中找到某一个节点 j ,它与它的父亲同样只有一条边相连,
它的s值与 i 的 s 值相等
它的最深回边所到的点是 i 的祖先
那么,只要减除i与i父亲的边,以及j与j父亲的边,即可形成新的联通分支。如下图所示的橙色边:
将有桥的方案和无桥的方案相加,即可得出总方案数。
#include<iostream> #include<cstdio> #include<cstring> #include<vector> using namespace std; const int maxn=2005; struct Edge { int a,b; }; vector<Edge>edges; vector<int>G[maxn]; int deep[maxn]; int t[maxn]; int s[maxn]; short lowset[maxn][maxn]; void add(int a,int b){ Edge e;e.a=a;e.b=b; edges.push_back(e); e.a=b;e.b=a; edges.push_back(e); G[a].push_back(edges.size()-2); G[b].push_back(edges.size()-1); } int bridge; int nobridge; void init(int n){ bridge=nobridge=0; memset(deep,-1,sizeof(deep)); memset(t,0,sizeof(t)); memset(s,0,sizeof(s)); for(int i=0;i<=n;i++)G[i].clear(); edges.clear(); } int check(int u,int fa){ int cnt=0; for(int i=0;i<G[fa].size();i++){ if(edges[G[fa][i]].b==u)cnt++; } return cnt; } bool Vis[maxn]; void push_down(int u,int su,int du){ for(int i=0;i<G[u].size();i++){ int v=edges[G[u][i]].b; if(deep[v]!=deep[u]+1)continue; if(Vis[v])continue; Vis[v]=true; if(check(v,u)==1&&su==s[v]&&t[v]<du){ nobridge++; } push_down(v,su,du); } } void dfs(int u,int fa,int No,int dep){ memset(lowset[u],0,sizeof(lowset[u])); deep[u]=dep; s[u]=1; t[u]=1; for(int i=0;i<G[u].size();i++){ if(G[u][i]==(No^1))continue; int v=edges[G[u][i]].b; if(deep[v]==-1){ dfs(v,u,G[u][i],dep+1); for(int j=1;j<dep;j++){ if(lowset[v][j])lowset[u][j]+=lowset[v][j]; } } else if(deep[v]<deep[u]){ lowset[u][deep[v]]++; } } for(int i=1;i<dep;i++){ if(lowset[u][i]){ s[u]+=lowset[u][i]; t[u]=t[u]>i?t[u]:i; } } if(fa==0)s[u]=0; if(s[u]==1) bridge++; else if(s[u]==2) nobridge++; if(s[u]!=0&&s[u]!=1&&check(u,fa)==1){ memset(Vis,0,sizeof(Vis)); push_down(u,s[u],deep[u]); } } void read_int(int&x) { char ch=getchar(); while(ch<'0'||ch>'9') ch=getchar(); x = ch - '0'; ch=getchar(); while('0'<=ch&&ch<='9') { x = 10*x + ch-'0'; ch = getchar(); } } int main(){ int n,m,a,b; while(scanf("%d%d",&n,&m)!=EOF){ init(n); for(int i=0;i<m;i++){ read_int(a); read_int(b); add(a,b); } dfs(1,0,-1,1); int res=bridge*(m-bridge)+(bridge*(bridge-1))/2; printf("%d\n",res+nobridge); } return 0; } /* 5 7 1 2 2 3 3 4 3 4 3 4 4 5 5 1
<span style="font-family: Arial, Helvetica, sans-serif;">ans = 6</span>
*/
相关文章推荐
- 【枚举+小技巧】【TOJ4115】【Find the number】
- CM12.1源码编译并刷机到三星N5100
- 轻应用 lapp
- 关于android程序运行时死打问题
- KALI屏幕录像
- python学习笔记——Tkinter GUI编程——简介
- Computer Networks A System Approach
- 程序日志--ios“打开网页url连接”程序
- 记中兴软件园一个月实训(三)
- KALI屏幕录像
- JavaScript实现的类字典插入或更新方法实例
- linux之cp/scp命令+scp命令详解
- SQL Server执行计划的理解
- 获取iframe的url
- 一个简单的网络框架
- javascirpt 的一些在IE下不支持的函数小结
- MongoDB oplog 深入剖析
- Could not flush the DNS Resolver Cache: 执行期间,函数出了问题
- http协议中:GET/POST/PUT/DELETE/INPUT/TRACE/OPTIONS/HEAD方法
- Home键和Back键的Android生命周期总结与比较