UVA 6907 Body Building Tarjan找桥

题目描述:

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

题目分析:

给定一个哑铃图的定义:由两个相同的完全图和一个桥构成。如题目描述的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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值