LOJ-10095(缩点的特殊使用)

题目链接:传送门

思路:

缩点求最值,但是有一点行不通,如果被选中的点才能缩点,否则缩点没有意义;

所以就先缩选中的点,然后从小到大统计没有缩点的点,就是NO;

如果找最小值,就是一个环里的最小值,然后求和就好了。

注意:

(1)预处理si和mon

(2)对选中的点缩点,不然全部缩点后比较麻烦

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 500100;
const int INF = 99999999;
int head[maxn],next[maxn],ver[maxn],tot;
int num[maxn],low[maxn],co[maxn],tim,col,si[maxn];
int st[maxn],top;
int mon[maxn],in[maxn];
int MIN(int x,int y)
{
    return x<y?x:y;
}
void Init()
{
    for(int i=0;i<maxn;i++) si[i]=INF,mon[i]=INF;
    tot=0;col=0;tim=0;top=0;
}
void addedge(int u,int v)
{
    ver[++tot]=v;next[tot]=head[u];head[u]=tot;
}
void Tarjan(int u)
{
    int i,v;
    low[u]=num[u]=++tim;
    st[++top]=u;
    for(i=head[u];i;i=next[i]){
        v=ver[i];
        if(!num[v]){
            Tarjan(v);
            low[u]=MIN(low[u],low[v]);
        } 
        else if(!co[v]) low[u]=MIN(low[u],num[v]);
    }
    if(low[u]==num[u]){
        col++;
        co[u]=col;
        si[col]=mon[u];
        while(st[top]!=u){
            si[col]=MIN(si[col],mon[st[top]]);
            co[st[top]]=col;
            top--;
        }
        top--;
    }
}
int main(void)
{
    int i,j,x,y,n,pp,rr;
    scanf("%d%d",&n,&pp);
    Init();
    for(i=1;i<=pp;i++){
        scanf("%d%d",&x,&y);
        mon[x]=y;
    }
    scanf("%d",&rr);
    for(i=1;i<=rr;i++){
        scanf("%d%d",&x,&y);
        addedge(x,y);
    }
    
    for(i=1;i<=n;i++)
    if(!num[i]&&mon[i]!=INF) Tarjan(i);
    
    for(i=1;i<=n;i++)
    if(!num[i]){
        printf("NO
%d",i);
        return 0;
    }
    for(i=1;i<=n;i++){
        for(j=head[i];j;j=next[j]){
            if(co[i]!=co[ver[j]]){
                in[co[ver[j]]]++;
            }
        }
    }
    
    int ans=0;
    for(i=1;i<=col;i++)
    if(in[i]==0) ans+=si[i];
    printf("YES
%d",ans);
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/2018zxy/p/10368942.html