题目描述:
题目分析:
给定一个哑铃图的定义:由两个相同的完全图和一个桥构成。如题目描述的A图B图和C图。
给一个图(有可能不连通),求有多少个哑铃图。
这题的n和m太小了,所以可以暴力每一条边,把这条边当做桥。
也可以用tarjan求桥。
最后就是判定桥两边的子图是否是相同的完全图,也就是他们的边数和点数是否相等,并且边数和点数满足完全图条件就可以。
分别以桥的两个端点,一个当做起点另一个为终点,dfs就可以。
代码如下:
1、遍历每一个点(vector写法)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <vector>
const int MAXN=110;
using namespace std;
int T;
int n,m;
bool vis[MAXN];
vector<int> G[MAXN];
void dfs(int u,int v,int &dep,int &num)
{
dep++; num+=G[u].size();
vis[u]=true;
for(int i=0; i<G[u].size(); i++)
{
int vv=G[u][i];
if (vv==v || vis[vv]) continue;
dfs(vv,v,dep,num);
}
}
bool judge(int u,int v)
{
memset(vis,0,sizeof(vis));
int dep1=0,num1=0;
dfs(u,v,dep1,num1);
memset(vis,0,sizeof(vis));
int dep2=0,num2=0;
dfs(v,u,dep2,num2);
return dep1==dep2 && num1==num2 && dep1*(dep1-1)==num1-1;
}
int main()
{
while(scanf("%d",&T)!=-1)
{
for(int t=1; t<=T; t++)
{
int ans=0;
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++) G[i].clear();
for(int i=1; i<=m; i++)
{
int u,v;
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
for(int u=1; u<=n; u++)
{
for(int i=0; i<G[u].size(); i++)
{
ans+=judge(u,G[u][i]);
}
}
printf("Case #%d: %d\n",t,ans>>1);
}
}
return 0;
}
2、Tarjan求桥(前向星写法)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <vector>
const int MAXN=110;
const int MAXM=10010;
using namespace std;
int T;
int n,m;
bool vis[MAXN];
struct Edge
{
int to,next;
bool cut;
} edge[MAXM];
int head[MAXN],tot;
int Low[MAXN],DFN[MAXN],Stack[MAXN];
int Index,top;
bool Instack[MAXN];
bool cut[MAXN];
int add_block[MAXN];
int bridge;
int ans;
int sum(int u,int pre)
{
if (vis[u]) return 0;
vis[u]=true;
int ans=1;
for(int i=head[u]; i!=-1; i=edge[i].next)
{
int v=edge[i].to;
if (v==pre) continue;
ans+=sum(v,u);
}
return ans;
}
int sumE(int u,int pre)
{
if (vis[u]) return 0;
vis[u]=true;
int ans=0;
for(int i=head[u]; i!=-1; i=edge[i].next)
{
ans++;
int v=edge[i].to;
if (v==pre) continue;
ans+=sumE(v,u);
}
return ans;
}
void addedge(int u,int v)
{
edge[tot].to=v;
edge[tot].next=head[u];
edge[tot].cut=false;
head[u]=tot++;
}
void Tarjan(int u,int pre)
{
int v;
Low[u]=DFN[u]=++Index;
Stack[top++]=u;
Instack[u]=true;
int son=0;
for(int i=head[u]; i!=-1; i=edge[i].next)
{
v=edge[i].to;
if (v==pre) continue;
if (!DFN[v])
{
son++;
Tarjan(v,u);
if (Low[u]>Low[v]) Low[u]=Low[v];
if (Low[v]>DFN[u])
{
bridge++;
edge[i].cut=true;
edge[i^1].cut=true;
}
if (u!=pre && Low[v]>=DFN[u])
{
cut[u]=true;
add_block[u]++;
}
}
else if (Low[u]>DFN[v]) Low[u]=DFN[v];
}
if (u==pre && son>1) cut[u]=true;
if (u==pre) add_block[u]=son-1;
Instack[u]=false;
top--;
}
void init()
{
tot=0;
memset(head,-1,sizeof(head));
}
int main()
{
while(scanf("%d",&T)!=-1)
{
for(int t=1; t<=T; t++)
{
init();
scanf("%d%d",&n,&m);
memset(DFN,0,sizeof(DFN));
memset(Instack,false,sizeof(Instack));
memset(add_block,0,sizeof(add_block));
memset(cut,false,sizeof(cut));
Index=top=0;
bridge=0;
for(int i=1; i<=m; i++)
{
int u,v;
scanf("%d%d",&u,&v);
addedge(u,v);
addedge(v,u);
}
int ret=0;
for(int i=1; i<=n; i++)
if (!DFN[i])
{
Tarjan(i,i);
int tmp=0;
for(int u=1; u<=n; u++)
{
for(int ii=head[u]; ii!=-1; ii=edge[ii].next)
{
int v=edge[ii].to;
if (edge[ii].cut)
{
edge[ii].cut=false;
memset(vis,0,sizeof(vis));
int t1=sum(u,v),t2=sum(v,u);
if (t1==t2)
{
memset(vis,0,sizeof(vis));
if (sumE(u,v)==t1*(t1-1)+1 && sumE(v,u)==t2*(t2-1)+1) tmp++;
}
}
}
}
if (tmp>0) ret++;
}
printf("Case #%d: %d\n",t,ret);
}
}
return 0;
}