您的位置:首页 > 其它

poj 1523 SPE

2012-05-29 17:04 323 查看
http://poj.org/problem?id=1523

居然1A and 0ms 太让我意外了

题目大意:

给你几个电脑的双相连通图 问你是否存在割点 如果存在输出割点并输出此割点见原图变成了几个块

输入输出只要注意就是了 没别的办法

Tarjan 算法 我就不多说了 我也说不好

总之用Tarjan算法找割点 但是你搜索时的根结点要特判

对不每个割点用dfs求其可把原图分成几个块

从割点发出可能用k个分支 那么块数 <= k

对其分支进行深搜并记录 有几个分支可以向下搜 就有几个块

深搜记录 可以搞定几个分支相连的情况

详情见代码注释:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<stack>
#include<algorithm>

using namespace std;
const int N=1005;
const int M=10000005;
struct node
{
struct tt *next;
}mem
;
struct tt
{
struct tt *next;
int j;
};
int had
;//割点是否已保存
int cutpoint
;//保存割点
int I;//割点数目
int deep;//深度 (时间戳)
bool visited
;
stack<int>str;
bool in
;
int low
;
int dfn
;
int st;//开始搜的起始点
void build(int i,int j)
{
struct tt *t=new tt;
t->j=j;
t->next=mem[i].next;
mem[i].next=t;
}
void Clear()//每次对表头进行清理
{
for(int i=0;i<N;++i)
mem[i].next=NULL;
}
void Tarjan(int x)
{
++deep;
low[x]=dfn[x]=deep;
visited[x]=true;
str.push(x);
in[x]=true;
struct tt *t=mem[x].next;
while(t!=NULL)
{
if(visited[t->j]==false)
{
Tarjan(t->j);
low[x]=min(low[x],low[t->j]);
}else if(in[t->j])
{
low[x]=min(low[x],dfn[t->j]);
}
if(!had[x]&&low[t->j]>=dfn[x]&&x!=st)//如果此点没记录 且为割点
{//但是不能等于起始点 因为起始点得进行特判
had[x]=true;
cutpoint[I]=x;
++I;
}
t=t->next;
}
if(low[x]==dfn[x])//对以x为根的强连通图进行出栈处理
{
while(str.top()!=x)
{
in[str.top()]=false;
str.pop();
}
in[str.top()]=false;
str.pop();
}
}
void dfs(int x)//深搜并记录
{
visited[x]=true;
struct tt *t=mem[x].next;
while(t!=NULL)
{
if(visited[t->j]==false)
dfs(t->j);
t=t->next;
}
}
int findnum(int x)
{
memset(visited,false,sizeof(visited));
visited[x]=true;
struct tt *t=mem[x].next;
int num=0;
while(t!=NULL)
{
if(visited[t->j]==false)//有多少分支是可搜的
{
++num;
dfs(t->j);
}
t=t->next;
}
return num;
}
int main()
{
int i,j;
for(int w=1;;++w)
{
st=M;
while(scanf("%d",&i),i)
{
scanf("%d",&j);
if(st==M)
st=j;
build(i,j);
build(j,i);
}
if(st==M)
break;
I=0;
if(findnum(st)>1)//对起始点进行特判 看它有多少不相连分支
{
had[st]=true;
cutpoint[I]=st;
++I;
}
deep=0;
while(!str.empty())
str.pop();
memset(in,false,sizeof(in));
memset(visited,false,sizeof(visited));
memset(had,false,sizeof(had));
Tarjan(st);
printf("Network #%d\n",w);
if(I==0)
{
printf("  No SPF nodes\n");
}
else
{
sort(cutpoint,cutpoint+I);
for(int i=0;i<I;++i)
{
printf("  SPF node %d leaves %d subnets\n",cutpoint[i],findnum(cutpoint[i]));
}
}
printf("\n");
Clear();
}
return 0;
}


更令我意外的是 直接用dfs 就能过 时间 16ms

每次对每个点进行判定 如果从他出发的分支有多余一个是可搜的 则是割点 且有多少是可搜的 就有多少块

其实就是对上面程序中对起始点特判的方法 无语了

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<stack>
#include<algorithm>

using namespace std;
const int N=1001;
const int M=10000005;
struct node
{
struct tt *next;
}mem
;
struct tt
{
struct tt *next;
int j;
};
int I;//割点数目
bool visited
;
bool had
;
void build(int i,int j)
{
struct tt *t=new tt;
t->j=j;
t->next=mem[i].next;
mem[i].next=t;
}
void Clear()//每次对表头进行清理
{
for(int i=0;i<N;++i)
mem[i].next=NULL;
}
void dfs(int x)//深搜并记录
{
visited[x]=true;
struct tt *t=mem[x].next;
while(t!=NULL)
{
if(visited[t->j]==false)
dfs(t->j);
t=t->next;
}
}
int findnum(int x)
{
memset(visited,false,sizeof(visited));
visited[x]=true;
struct tt *t=mem[x].next;
int num=0;
while(t!=NULL)
{
if(visited[t->j]==false)//有多少分支是可搜的
{
++num;
dfs(t->j);
}
t=t->next;
}
// cout<<x<<" "<<num<<endl;
return num;
}
int main()
{
int i,j;
for(int w=1;;++w)
{
memset(had,false,sizeof(had));
j=-1;
while(scanf("%d",&i),i)
{
scanf("%d",&j);
had[i]=had[j]=true;
build(i,j);
build(j,i);
}
if(j==-1)
break;
printf("Network #%d\n",w);
I=0;
for(int i=1;i<N;++i)
{
if(had[i]==false)
continue;
int k=findnum(i);
if(k>1)
{
++I;
printf("  SPF node %d leaves %d subnets\n",i,k);
}
}
if(I==0)
{
printf("  No SPF nodes\n");
}
printf("\n");
Clear();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: