POJ 1144 Network
求有几个割点。数据比较水,用了朴素方法。。。30ms。。。
#include<cstdio> #include<cstring> #include<cmath> #include<vector> #include<algorithm> using namespace std; char s[1000000]; int n,u,v,tot,len,sum; const int INF=0x7FFFFFFF; const int MAXN=105; vector<int>G[MAXN]; int fail[MAXN],flag[MAXN]; void DFS(int now) { int i; for(i=0; i<G[now].size(); i++) { if(!flag[G[now][i]]&&!fail[G[now][i]]) { flag[G[now][i]]=1; DFS(G[now][i]); } } } int main() { int i,ii; while(~scanf("%d",&n)&&n) { for(i=0; i<=n; i++) G[i].clear(); memset(flag,0,sizeof(flag)); memset(fail,0,sizeof(fail)); while(gets(s)) { if(strcmp(s,"0")==0) break; len=strlen(s); u=INF; sum=0; for(i=0; i<=len; i++) { if(s[i]==' '||s[i]=='\0') { if(u==INF) u=sum,sum=0; else { v=sum,sum=0; G[u].push_back(v); G[v].push_back(u); } } else sum=sum*10+s[i]-'0'; } } memset(fail,0,sizeof(fail)); int AAA,ans=0; for(ii=1; ii<=n; ii++) { fail[ii]=1; AAA=0; memset(flag,0,sizeof(flag)); for(i=1; i<=n; i++) { if(fail[i]) continue; if(!flag[i]) { flag[i]=1; DFS(i); AAA++; } } if(AAA!=1) ans++; fail[ii]=0; } printf("%d\n",ans); } return 0; }
下面是用Tarjan算法的。跑了500ms的样子。。。。。。
#include<cstdio> #include<cstring> #include<cmath> #include<vector> #include<algorithm> using namespace std; const int INF=0x7FFFFFFF; const int maxn=1111;//有多少个结点 vector<int>G[maxn]; int visited[maxn];//标记该节点有没有访问过 int node,edge;//顶点数目 int tmpdfn;//dfs过程中记录当前的深度优先搜索序数 int dfn[maxn];//记录每个顶点的深度优先搜索序数 int low[maxn];//每个顶点的low值,根据该值来判断是否是关节点 int son;//根结点的有多少个孩子,如果大于等于2,则根结点为关节点 int subnets[maxn];//记录每个结点(去掉该结点后)的连通分量的个数 char s[maxn]; /*以下是输出重连通分量用的*/ int top; struct Edge { int u,v; void output() { printf("%d-%d ",u,v); } bool cmp(Edge &t) { return ((u==t.u&&v==t.v)||(v==t.u&&u==t.v)); } }; Edge Stack[maxn]; int Flag[maxn][maxn]; void init() { for(int i=0; i<maxn; i++) G[i].clear(); low[1]=dfn[1]=1; tmpdfn=1; son=0; memset(visited,0,sizeof(visited)); visited[1]=1; memset(subnets,0,sizeof(subnets)); } void dfs(int u) { for(int i=0; i<G[u].size(); i++) { int v=G[u][i]; Edge t; /*将这条边压入栈顶*/ if(!Flag[u][v])//没有入过栈 { t.u=u; t.v=v; Stack[++top]=t; Flag[u][v]=Flag[v][u]=1; } if(!visited[v]) { visited[v]=1; tmpdfn++; dfn[v]=low[v]=tmpdfn; dfs(v); low[u]=min(low[u],low[v]); if(low[v]>=dfn[u]) { if(u!=1) subnets[u]++; if(u==1) son++; /* printf("重连通分量:"); while(1) { if(top==-1) break; Edge t1; t1=Stack[top]; t1.output(); top--; if(t1.cmp(t)) break; } printf("\n"); */ } } else low[u]=min(low[u],dfn[v]); } } int main() { while(~scanf("%d",&node)&&node)//输入节点数量和边的数量 { init();//初始化 int len,u,v,sum; while(gets(s)) { if(strcmp(s,"0")==0) break; len=strlen(s); u=INF; sum=0; for(int i=0; i<=len; i++) { if(s[i]==' '||s[i]=='\0') { if(u==INF) u=sum,sum=0; else { v=sum,sum=0; G[u].push_back(v); G[v].push_back(u); } } else sum=sum*10+s[i]-'0'; } } top=-1;//初始化 栈为空 memset(Flag,0,sizeof(Flag)); //DFS求解割点,点双连通分量,去掉一个个点之后有几个连通分量 /*DFS过程中输出点双连通分量*/ dfs(1); //计算根节点 if(son>1) subnets[1]=son-1; int ans=0; /*输出割点*/ for(int i=1; i<=node; i++) if(subnets[i]) //printf("%d号节点是割点,删除之后有%d个连通分量\n",i,subnets[i]+1); ans++; printf("%d\n",ans); } return 0; }