强连通图,Tarjan——CodeForces - 427C

题目链接

题目含义

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

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

题目分析

使用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\n",sum,sumn);
    return 0;
}

 

posted @ 2019-08-01 22:05  helman78  阅读(301)  评论(0编辑  收藏  举报