洛谷 1262 间谍网络——缩点+拓扑

题目:https://www.luogu.org/problemnew/show/P1262

当然是缩点。一个点的收买价就是旗下点的最小值。然后从入度为0的点挨个dfs。

但其实不对。可能入度为0的那个开头是不能收买的,但后面一个有入度的点可以收买。

所以应该像拓扑排序那样遍历每个点。注意打过vis标记就不再算了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=3005,M=8005,INF=0x3f3f3f3f;
int n,p,m,a[N],hd[N],xnt,to[M],nxt[M],fr[M];
int dfn[N],low[N],tim,col[N],cnt,rd[N],c[N];
int ans,sta[N],top,q[N],he,tl;
bool ins[N];
struct Ed{
    int nxt,to;Ed(int n=0,int t=0):nxt(n),to(t) {}
}ed[M];
int rdn()
{
    int ret=0;bool fx=1;char ch=getchar();
    while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}
    while(ch>='0'&&ch<='9') ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar();
    return fx?ret:-ret;
}
void add(int x,int y)
{
    to[++xnt]=y; nxt[xnt]=hd[x]; hd[x]=xnt; fr[xnt]=x;
}
void ade(int x,int y)
{
    ed[++xnt]=Ed(hd[x],y); hd[x]=xnt; rd[y]++;
}
void tarjan(int cr)
{
    dfn[cr]=low[cr]=++tim;
    sta[++top]=cr; ins[cr]=1;
    for(int i=hd[cr],v;i;i=nxt[i])
    {
        if(!dfn[v=to[i]])
            tarjan(v),low[cr]=min(low[cr],low[v]);
        else if(ins[v])
            low[cr]=min(low[cr],dfn[v]);
    }
    if(dfn[cr]==low[cr])
    {
        cnt++; c[cnt]=INF;
        while(sta[top]!=cr)
        {
            int k=sta[top--];
            col[k]=cnt; ins[k]=0;
            c[cnt]=min(c[cnt],a[k]);
        }
        top--; col[cr]=cnt; ins[cr]=0;
        c[cnt]=min(c[cnt],a[cr]);
    }
}
void dfs(int cr)
{
    ins[cr]=1;
    for(int i=hd[cr];i;i=ed[i].nxt)
        dfs(ed[i].to);
}
int main()
{
    n=rdn(); p=rdn();
    memset(a,0x3f,sizeof a);
    for(int i=1,u;i<=p;i++)
    {
        u=rdn();a[u]=rdn();
    }
    m=rdn();
    for(int i=1,u,v;i<=m;i++)
    {
        u=rdn(); v=rdn(); add(u,v);
    }
    for(int i=1;i<=n;i++)
        if(!dfn[i]) tarjan(i);
    xnt=0;
    memset(hd,0,sizeof hd);
    for(int i=1;i<=m;i++)
        if(col[to[i]]!=col[fr[i]])
            ade(col[fr[i]],col[to[i]]);
    memset(ins,0,sizeof ins);
    for(int i=1;i<=cnt;i++)
        if(!rd[i])
            q[++tl]=i;
    while(he<tl)
    {
        int k=q[++he];
        if(c[k]<INF&&!ins[k]) ans+=c[k],dfs(k);
        for(int i=hd[k],v;i;i=ed[i].nxt)
        {
            rd[v=ed[i].to]--;
            if(!rd[v]) q[++tl]=v;
        }
    }
    for(int i=1;i<=n;i++)
        if(!ins[col[i]])
        {
            printf("NO\n%d\n",i);
            return 0;
        }
    printf("YES\n%d\n",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Narh/p/9702848.html
今日推荐