连通问题

HDU 1269

题意:

如果图中任意两点可以互相到达输出Yes,反之No

解析:

判断强连通分量是否为1

ac:

#include
#define MAXN 100005
using namespace std;
#define inf 0x3f3f3f3f

vector g[MAXN];
int color[MAXN],dfn[MAXN],low[MAXN],stck[MAXN],vis[MAXN];
int deep,top,n,m,sum,a,b;

void tarjan(int u)
{
    dfn[u]=++deep;
    low[u]=deep;
    vis[u]=1;
    stck[++top]=u;
    int sz=g[u].size();
    for(int i=0;i1)
            printf("No\n");
        else
            printf("Yes\n");
    }
}

https://vjudge.net/problem/POJ-3177

题意:

给定一个无向连通图,问加多少条边可以使得图变成一个边双连通图

解析:

先求出边双连通,然后缩点,缩点后,将叶子结点相连

结果为:(ans+1)/2;(ans:叶子结点数目)

ac:

#include
#include
#include
#include
#include
#define MAXN 200005
using namespace std;
int to[MAXN<<1],nxt[MAXN<<1],head[MAXN<<1];
int tot,cnt;
int dfn[MAXN],low[MAXN];
int vis[MAXN<<1];

void init()
{
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(vis,0,sizeof(vis));
    memset(head,0,sizeof(head));
    tot=1,cnt=0;
}

void add(int u,int v)
{
    to[++tot]=v;
    nxt[tot]=head[u];
    head[u]=tot;
}

void tarjan(int x,int fa)
{
    dfn[x]=low[x]=++cnt;
    for(int i=head[x];i;i=nxt[i])
    {
        int v=to[i];
        if(dfn[v]==0)
        {
            tarjan(v,i);
            low[x]=min(low[x],low[v]);
            if(low[v]>dfn[x]){
                vis[i]=vis[i^1]=1;
            }
        }
        else if(i!=(fa^1)){
            low[x]=min(low[x],dfn[v]);
        }
    }
}
int u[MAXN<<1],v[MAXN<<1];
vector vc[MAXN];

int c[MAXN],dcc;

void dfs(int x)
{
    c[x]=dcc;
    for(int i=0;i

https://www.luogu.org/problem/P2341

题意:

将图缩成若干强连通分量

如果一个强连通分量的入度为1,且仅有1个,呢么这个强连通分量里的个数就是答案

ac:

#include
#define MAXN 200005
using namespace std;
int to[MAXN<<1],nxt[MAXN<<1],head[MAXN<<1];
int tot,cnt;
int low[MAXN],dfn[MAXN],vis[MAXN];
stack st;
int stck[MAXN<<1],top;
int c[MAXN],in[MAXN],num;
int sz[MAXN];//对连通分量计数

void init()
{
    tot=1;
    top=num=cnt=0;
    memset(head,0,sizeof(head));
}

void add(int u,int v)
{
    to[++tot]=v;
    nxt[tot]=head[u];
    head[u]=tot;
}

void tarjan(int x)
{
    dfn[x]=low[x]=++cnt;
    vis[x]=1;
    st.push(x);
    for(int i=head[x];i;i=nxt[i])
    {
        int v=to[i];
        if(dfn[v]==0)
        {
            tarjan(v);
            low[x]=min(low[x],low[v]);
        }
        else{
            if(vis[v]!=0){
                low[x]=min(low[x],dfn[v]);
            }
        }
    }
    if(dfn[x]==low[x])
    {
        int k;
        ++num;
        do{
            k=st.top();st.pop();
            vis[k]=0;
            c[k]=num;
            sz[num]++;
        }while(x!=k);
    }
}

int main()
{
    init();
    int n,m,u,v;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
        scanf("%d%d",&u,&v),add(u,v);
    for(int i=1;i<=n;i++)
    {
        if(dfn[i]==0)
            tarjan(i);
    }
    for(int i=1;i<=n;i++){//遍历每条边,求每一连通分量的入度
        for(int j=head[i];j;j=nxt[j]){
            int v=to[j];
            if(c[i]!=c[v])
                in[c[i]]++;
        }
    }
    int ans=0,tt=0;
    for(int i=1;i<=num;i++)//入度为0且数量仅为1
    {
        if(in[i]==0)
        {
            tt++;
            ans=sz[i];
        }
    }
    if(tt==1)
        printf("%d\n",ans);
    else
        printf("0\n");
    return 0;
}

http://acm.hdu.edu.cn/showproblem.php?pid=1827

题意:

他想着得快点把这消息告诉大家,虽然他手上有所有人的联系方式,但是一个一个联系过去实在太耗时间和电话费了。

他知道其他人也有一些别人的联系方式,这样他可以通知其他人,再让其他人帮忙通知一下别人。

你能帮Wiskey计算出至少要通知多少人,至少得花多少电话费就能让所有人都被通知到吗?

解析:

我必须通知一些人,这些人打电话给其他人,最后通知了所以人,尽可能的选择必须的且在必须的里选择最小的

对于同一强连通分量,我可以选择里面的任何人,我应该选择里面最小的.

如果一个连通分量能被另外一个连通分量通知,我就不必通知这个连通分量,因为我要通知所以人,所以另一个连通分量应该被先通知.

将图缩点,将同一连通分量缩点,保存同一连通分量里val最小的,然后计算他们的度数,我们选择入度为0,入度为0的只能被我通知

ac:

#include
#define ll long long
#define MAXN 2005
using namespace std;
int to[MAXN<<1],head[MAXN<<1],nxt[MAXN<<1];
int tot;
int val[MAXN];
int dfn[MAXN],low[MAXN],cnt,vis[MAXN];
int c[MAXN];
int in[MAXN];
int com[MAXN],num;
stack sk;

void init()
{
    num=cnt=0;
    tot=1;
    for(int i=0;i

 

你可能感兴趣的:(强连通分量&双连通)