zoukankan      html  css  js  c++  java
  • 强连通图,Tarjan——CodeForces

    题目链接

    题目含义

    给出一个图,每个强连通图都要寻找一个点

    要求寻找的点的价值之和最少,并且问这个最低价值有几种选法

    题目分析

    使用Tarjan算法,每次找到一个强连通图时出栈,并在出栈过程寻找最低价值的点和这个点的个数

    最后把每个强连通图的最低价值加起来,个数都相乘就得到最后答案

    有一个需要注意的点——

    平时都可以把instack[x]=0写在if(dfn[x]==low[x])前面,因为当改变了x的instack后,其他位置就无法通过访问x访问x的子树,但是这道题我用了一个dfs访问每一个可能存在的强连通图找答案,后寻找的点可能是前面寻找过的点的子树点,前面没还原的instack可能会影响后面的值

    所以要么把instack写在退栈循环里,要么给dfs加上一个初始化instack=0

    别问我为什么instack=0不能写在if前面

    题目代码

    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    using namespace std;
    typedef long long LL;
    const int maxn=1e5+7;
    const int mod=1e9+7;
    const int INF=0x3f3f3f3f;
    struct edge{
        int to,next;
    }e[maxn*3];
    int head[maxn],minc[maxn],nway[maxn],st[maxn],instack[maxn],low[maxn],dfn[maxn],cost[maxn];
    int n,m,a,b,top,cnt,scc,tot;
    void add(int u,int v){
        e[tot].to=v;
        e[tot].next=head[u];
        head[u]=tot++;
    }
    void init(){
        memset(head,-1,sizeof(head));
    }
    void Tarjan(int x){
        st[++top]=x;
        instack[x]=1;
        low[x]=dfn[x]=++cnt;
        for(int i=head[x];i!=-1;i=e[i].next){
            int y=e[i].to;
            if(!dfn[y]){
                Tarjan(y);
                low[x]=min(low[x],low[y]);
            }
            else if(instack[y])low[x]=min(low[x],dfn[y]);
        }
        if(dfn[x]==low[x]){
            int p=-1;
            scc++;
            minc[scc]=INF;
            do{
                p=st[top];
                instack[p]=0;
                if(cost[p]<minc[scc]){
                    minc[scc]=cost[p];
                    nway[scc]=1;
                }
                else if(cost[p]==minc[scc])
                    nway[scc]++;
                top--;
            }while(st[top+1]!=x);
        }
    }
    void dfs(){
        for(int i=1;i<=n;i++)
            if(!dfn[i])Tarjan(i);
    }
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d",&cost[i]);
        scanf("%d",&m);
        init();
        for(int i=1;i<=m;i++){
            scanf("%d%d",&a,&b);
            add(a,b);
        }
        dfs();
        LL sum=0,sumn=1;
        for(int i=1;i<=scc;i++){
            sum+=minc[i];
            sumn=(sumn*nway[i])%mod;
        }
        printf("%lld %lld
    ",sum,sumn);
        return 0;
    }
  • 相关阅读:
    sublime text 安装json插件
    通过坐标系求覆盖物面积
    关于大数据入门的相关闲聊
    渡月橋 ~君 想ふ~
    数据库快照
    oracle 11g安装与使用
    IaaS、PaaS、SaaS介绍(非原创)
    Android项目模块化/组件化开发(非原创)
    开发人员必备的网络知识(非原创)
    公司常见管理系统介绍(非原创)
  • 原文地址:https://www.cnblogs.com/helman/p/11285688.html
Copyright © 2011-2022 走看看