强联通分量

从9.13开始做强联通分量,开始强联通还把我给困住了,因为两个方程:
1、low[u]=min{low[u],low[v]}

2、low[u]=min{low[u],dfn[v]}

多看网上的讲解和图就晓得了:

其实第一个就是在每一次tarjan(u)之后,第二个就是在找到搜索过程中找到了根节点时;

例题:间谍网络

https://loj.ac/problem/10095

算是一道有难度的题了吧,反正在打完模板之外还要进行一遍dfs。需要思考的有三:

1、怎样判断能否控制完

2、可以全部控制时,怎样选最小费用

3、无法全部控制时,怎样选最小编号

分析:缩点,成了一个有向无环图,dfs每个强联通子图,找入度为0的图,当这个子图中有能控制的人时,累加上。若遇到这个子图中没有能贿赂的人时,依然要dfs进行完,最后在for循环判断出最小编号即可(当然之前要对能控制的点标记~)

对于问题2,其实已经解决了

#include<bits/stdc++.h>
using namespace std;
int n,p,r;
struct node{
    int to,next;
}e[1100000];
int num=0,head[11000];
void add(int x,int y)
{
    e[++num].to=y;
    e[num].next=head[x];
    head[x]=num;
}
int fee[100000];
inline void read(int &x)
{
    x=0;int f=1;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){x=(x<<1)+(x<<3)+s-'0';s=getchar();}
    x*=f;
}
int dfn[10000],low[10000],co[10000],col,sta[10000],si[10000],top=0;
int jin[10000],lian[100000],bz[100000];
void tarjan(int u)
{
    low[u]=dfn[u]=++top;
    sta[top]=u;
    for(int i=head[u];i;i=e[i].next)
    {
        int v=e[i].to;
        if(!dfn[v]){
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else
        {
            if(!co[v]){
                low[u]=min(low[u],dfn[v]);
            }
        }
    }
    if(low[u]==dfn[u])
    {
        co[u]=++col;
        si[col]++;
        if(bz[u])lian[col]=u;
        while(sta[top]!=u)
        {
            if(bz[sta[top]]&&fee[sta[top]]<fee[lian[col]])
            {
                lian[col]=sta[top];
            }
            ++si[col];
            co[sta[top]]=col;
            top--;
        }
        top--;
    }
}
int vis[100000];
void dfs(int u)
{
    vis[u]=1;
    for(int i=head[u];i;i=e[i].next)
    {
        int v=e[i].to;
        if(!vis[v]){
            dfs(v);
        }
    }
}
int main()
{
    for(int i=0;i<100000;i++) {
        lian[i]=4000;
        fee[i]=99999;
    }
    scanf("%d%d",&n,&p);
    for(int i=1;i<=p;i++)
    {    
        int per,f;
        scanf("%d%d",&per,&f);
        bz[per]=1;
        fee[per]=f;
    }
    scanf("%d",&r);
    for(int i=1;i<=r;i++)
    {    
        int x,y; 
        scanf("%d%d",&x,&y);
        add(x,y);
    }
    for(int i=1;i<=n;i++)
    {
        if(!dfn[i])tarjan(i);
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=head[i];j;j=e[j].next)
        {
            int v=e[j].to;
            if(co[i]!=co[v])jin[co[v]]++;
        }
    }

    bool flag=1;
    int ans=0;
    for(int i=1;i<=col;i++)
    {
        if(!jin[i])
        {
            if(lian[i]!=4000)
            {
                ans+=fee[lian[i]];
                dfs(lian[i]);
            }
            else{
                flag=0;
            }
        }
    }
    if(flag)
    {
        printf("YES\n%d",ans);
        return 0;
    }
    for(int i=1;i<=n;i++)
    {
        if(!vis[i]){
            printf("NO\n%d",i);
            return 0;
        }
    }
}

 

posted @ 2018-09-14 22:42  南柯一场  阅读(121)  评论(0编辑  收藏  举报