Electricity POJ - 2117
题目描述
Blackouts and Dark Nights (also known as ACM++) is a company that provides electricity. The company owns several power plants, each of them supplying a small area that surrounds it. This organization brings a lot of problems - it often happens that there is not enough power in one area, while there is a large surplus in the rest of the country.
ACM++ has therefore decided to connect the networks of some of the plants together. At least in the first stage, there is no need to connect all plants to a single network, but on the other hand it may pay up to create redundant connections on critical places - i.e. the network may contain cycles. Various plans for the connections were proposed, and the complicated phase of evaluation of them has begun.
One of the criteria that has to be taken into account is the reliability of the created network. To evaluate it, we assume that the worst event that can happen is a malfunction in one of the joining points at the power plants, which might cause the network to split into several parts. While each of these parts could still work, each of them would have to cope with the problems, so it is essential to minimize the number of parts into which the network will split due to removal of one of the joining points.
Your task is to write a software that would help evaluating this risk. Your program is given a description of the network, and it should determine the maximum number of non-connected parts from that the network may consist after removal of one of the joining points (not counting the removed joining point itself).
输入格式
The input consists of several instances.
The first line of each instance contains two integers 1 <= P <= 10 000 and C >= 0 separated by a single space. P is the number of power plants. The power plants have assigned integers between 0 and P - 1. C is the number of connections. The following C lines of the instance describe the connections. Each of the lines contains two integers 0 <= p1, p2 < P separated by a single space, meaning that plants with numbers p1 and p2 are connected. Each connection is described exactly once and there is at most one connection between every two plants.
The instances follow each other immediately, without any separator. The input is terminated by a line containing two zeros.
输出格式
The output consists of several lines. The i-th line of the output corresponds to the i-th input instance. Each line of the output consists of a single integer C. C is the maximum number of the connected parts of the network that can be obtained by removing one of the joining points at power plants in the instance.
样例
Sample Input
3 3
0 1
0 2
2 1
4 2
0 1
2 3
3 1
1 0
0 0
Sample Output
1
2
2
题目大意
求删除一个点后所得连通分量数的最大值
分析
实际上我们只需要在割点中选取删除的点就可以了
为什么呢,因为割点的定义是这样的:在一个无向图中,如果有一个顶点集合,删除这个顶点集合以及这个集合中所有顶点相关联的边以后,图的连通分量增多,就称这个点集为割点集合。
所以,我们先Tarjan一下,求出所有的割点
那么对于每一个割点,如果我们都进行一次dfs的话,显然会T掉
所以我们考虑一下其他的方法
实际上,我们可以在进行Tarjan的过程中稍微做一下改动
我们把cut[i]重新定义为将割点i删除后增加的联通分量个数
每次遇到low[u]>=dfn[now]
我们就把cut[now]++
这样我们在统计结果时只需要枚举cut[i]的最大值就可以了
再把这个最大值加上原图中联通块的个数
要特别注意的是,对于根节点,要在最后把cut值减去一(想想这是为什么)
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn=400005;
int head[maxn],dfn[maxn],low[maxn],cut[maxn];
int tot=2,cnt=0;
struct asd{
int from,to,next;
}b[maxn];
void ad(int aa,int bb){
b[tot].from=aa;
b[tot].to=bb;
b[tot].next=head[aa];
head[aa]=tot++;
}
int dfnc;
void tarjan(int now,int fa){
low[now]=dfn[now]=++dfnc;
for(int i=head[now];i!=-1;i=b[i].next){
int u=b[i].to;
if(!dfn[u]){
tarjan(u,now);
low[now]=min(low[now],low[u]);
if(fa==-1) cut[now]++;
if(fa!=-1 && low[u]>=dfn[now]){
cut[now]++;
}
}
else if(u!=fa){
low[now]=min(low[now],dfn[u]);
}
}
}
int main(){
int m,n;
while(scanf("%d%d",&n,&m)!=EOF && n!=0){
memset(&b,0,sizeof(struct asd));
memset(head,-1,sizeof(head));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(cut,0,sizeof(cut));
dfnc=0,tot=1,cnt=0;
for(int i=1;i<=m;i++){
int aa,bb;
scanf("%d%d",&aa,&bb);
ad(aa,bb),ad(bb,aa);
}
for(int i=0;i<n;i++){
if(!dfn[i]){
tarjan(i,-1);
cut[i]--;
cnt++;
}
}
int ans=-0x3f3f3f3f;
for(int i=0;i<n;i++){
ans=max(ans,cut[i]);
}
printf("%d
",ans+cnt);
}
return 0;
}
SPF POJ - 1523
题目描述
Consider the two networks shown below. Assuming that data moves around these networks only between directly connected nodes on a peer-to-peer basis, a failure of a single node, 3, in the network on the left would prevent some of the still available nodes from communicating with each other. Nodes 1 and 2 could still communicate with each other as could nodes 4 and 5, but communication between any other pairs of nodes would no longer be possible.
Node 3 is therefore a Single Point of Failure (SPF) for this network. Strictly, an SPF will be defined as any node that, if unavailable, would prevent at least one pair of available nodes from being able to communicate on what was previously a fully connected network. Note that the network on the right has no such node; there is no SPF in the network. At least two machines must fail before there are any pairs of available nodes which cannot communicate.
Input
The input will contain the description of several networks. A network description will consist of pairs of integers, one pair per line, that identify connected nodes. Ordering of the pairs is irrelevant; 1 2 and 2 1 specify the same connection. All node numbers will range from 1 to 1000. A line containing a single zero ends the list of connected nodes. An empty network description flags the end of the input. Blank lines in the input file should be ignored.
Output
For each network in the input, you will output its number in the file, followed by a list of any SPF nodes that exist.
The first network in the file should be identified as "Network #1", the second as "Network #2", etc. For each SPF node, output a line, formatted as shown in the examples below, that identifies the node and the number of fully connected subnets that remain when that node fails. If the network has no SPF nodes, simply output the text "No SPF nodes" instead of a list of SPF nodes.
样例
Sample Input
1 2
5 4
3 1
3 2
3 4
3 5
0
//空格
1 2
2 3
3 4
4 5
5 1
0
//空格
1 2
2 3
3 4
4 6
6 3
2 5
5 1
0
//空格
0
Sample Output
Network #1
SPF node 3 leaves 2 subnets
//空格
Network #2
No SPF nodes
//空格
Network #3
SPF node 2 leaves 2 subnets
SPF node 3 leaves 2 subnets
分析
一样的套路,注意输出的时候要输出两个换行符
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn=100005;
int head[maxn],dfn[maxn],low[maxn],cut[maxn];
int tot=2,cnt=0;
struct asd{
int from,to,next;
}b[maxn];
void ad(int aa,int bb){
b[tot].from=aa;
b[tot].to=bb;
b[tot].next=head[aa];
head[aa]=tot++;
}
int dfnc;
void tarjan(int now,int fa){
low[now]=dfn[now]=++dfnc;
for(int i=head[now];i!=-1;i=b[i].next){
int u=b[i].to;
if(!dfn[u]){
tarjan(u,now);
low[now]=min(low[now],low[u]);
if(fa==-1) cut[now]++;
if(fa!=-1 && low[u]>=dfn[now]){
cut[now]++;
}
}
else if(u!=fa){
low[now]=min(low[now],dfn[u]);
}
}
}
bool jl[maxn];
int js;
int main(){
int m,n;
while(scanf("%d",&m)!=EOF && m!=0){
js++;
memset(&b,0,sizeof(struct asd));
memset(head,-1,sizeof(head));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(cut,0,sizeof(cut));
memset(jl,0,sizeof(jl));
dfnc=0,tot=1,cnt=0;
scanf("%d",&n);
ad(n,m),ad(m,n);
jl[m]=1,jl[n]=1;
int aa,bb;
while(scanf("%d",&aa)!=EOF && aa!=0){
scanf("%d",&bb);
ad(aa,bb),ad(bb,aa);
jl[aa]=1,jl[bb]=1;
}
for(int i=1;i<maxn;i++){
if(!dfn[i] && jl[i]){
tarjan(i,-1);
cnt++;
cut[i]--;
}
}
printf("Network #%d
",js);
int ans=0;
for(int i=1;i<maxn;i++){
if(cut[i] && jl[i]) ans++;
}
if(ans==0){
printf(" No SPF nodes
");
continue;
} else {
for(int i=1;i<maxn;i++){
if(cut[i] && jl[i]){
printf(" SPF node %d leaves %d subnets
",i,cut[i]+cnt);
}
}
}
printf("
");
}
return 0;
}