题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3749
借鉴了一位大佬的思路:https://blog.csdn.net/u013480600/article/details/31782327
题意:给你一个(保证输入无重边,无自环)无向图,然后有下面Q条询问,每条询问为:问你u点与v点之间有几条(除了首尾两点外,其他点不重复)的路径.如果有0条或1条输出0或1,如果有2条以上,输出”two or more”.
分析:
1、首先如果u点与v点不连通,直接输出0即可.(用并查集实现)
2 、然后如果u点与v点属于同一个点-双连通分量,输出two or more.(这里有特例,两点一边的点-双连通分量应该输出1)
3.、 剩下的所有情况表示u与v虽然连通,但是在不同的点-双连通分量类,直接输出1即可.
Q:如果该题仅要求u与v的不同路径边不同即可,情况又是如何呢?(这种情况更简单,只需考虑边-双连通分量即可且没有特例)
代码如下:
#include <iostream>
#include <math.h>
#include <stdlib.h>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#include <stdio.h>
#include <string.h>
#include <stack>
using namespace std;
const int maxn=5000+5;
int n,m,q;
int dfs_clock,pre[maxn],bcc_cnt,iscut[maxn],bccno[maxn],fa[maxn];//bcc_cnt为点-双连通分量的标号
// bccno[i]=x表示第i个顶点属于x号点双连通分量
vector<int>G[maxn],bcc[maxn],belong[maxn];//bcc[i].size()表示包含了i号 点-双连通分量的所有点
//belong[i]表示i点属于哪些 点-双连通分量
struct Edge
{
int u,v;
Edge(int u,int v):u(u),v(v){};
};
stack<Edge> S;
void init()
{
dfs_clock=bcc_cnt=0;
memset(pre,0,sizeof(pre));
memset(bccno,0,sizeof(bccno));
memset(iscut,0,sizeof(iscut));
for(int i=0; i<n; i++)
{
G[i].clear();
belong[i].clear();
fa[i]=i;
}
}
int find_(int x)
{
return x==fa[x]? x : fa[x]=find_(fa[x]);
}
int dfs(int u, int fa)
{
int lowu= pre[u]= ++dfs_clock;
int child =0;
for(int i=0; i<G[u].size(); i++)
{
int v=G[u][i];
Edge e =Edge(u,v);
if(!pre[v])
{
S.push(e);
child++;
int lowv =dfs(v,u);
lowu=min(lowu,lowv);
if(lowv >=pre[u])
{
iscut[u]=1;
bcc_cnt++;
bcc[bcc_cnt].clear();
while(true)
{
Edge x=S.top();
S.pop();
if(bccno[x.u]!=bcc_cnt)
{
bcc[bcc_cnt].push_back(x.u);
bccno[x.u]=bcc_cnt;
belong[x.u].push_back(bccno[x.u]);
}
if(bccno[x.v]!=bcc_cnt)
{
bcc[bcc_cnt].push_back(x.v);
bccno[x.v]=bcc_cnt;
belong[x.v].push_back(bccno[x.v]);
}
if(x.u==u&&x.v==v)
break;
}
}
}
else if(pre[v]<pre[u]&&v!=fa)
{
S.push(e);
lowu=min(lowu,pre[v]);
}
}
if(fa<0&&child==1)
iscut[u]=0;
return lowu;
}
int main()
{
int k=0;
while(scanf("%d %d %d",&n,&m,&q)&&(n+m+q))
{
init();
int u,v;
for(int i=0; i<m; i++)
{
scanf("%d %d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
int fa1,fa2;
fa1=find_(u),fa2=find_(v);
if(fa1!=fa2)
fa[fa1]=fa2;
}
for(int i=0; i<n; i++)
{
if(!pre[i])
dfs(i,-1);
}
printf("Case %d:\n",++k);
for(int i=0; i<q; i++)
{
int flag=1;
scanf("%d %d",&u,&v);
int fa1,fa2;
fa1=find_(u),fa2=find_(v);
if(fa1!=fa2)
{
printf("zero\n");
continue;
}
for(int i=0; i<belong[u].size(); i++)
{
if(flag==0)
break;
for(int j=0; j<belong[v].size(); j++)
{
if(belong[u][i]==belong[v][j])
{
if(bcc[belong[u][i]].size()!=2)//排除特例 两点一边的情况
{
flag=0;
break;
}
}
}
}
if(flag)
printf("one\n");
else
printf("two or more\n");
}
}
return 0;
}