【题解】洛谷P1262 间谍网络 (强连通分量缩点)

洛谷P1262:https://www.luogu.org/problemnew/show/P1262

思路

一看题目就知道是强连通分量缩点

当图中有强连通分量时 将其缩点 

我们可以用dfn数组判断是否可以达到所有人都可以控制

到最后图中可能有如下2种情况

First 整个图为一个强连通分量 ans即是能贿赂的最小值

Second 当图中有链时 贿赂链的第一个人即可取得最小值

代码

#include<iostream>
#include<cstring>
using namespace std;
#define maxn 3010
#define INF 1e9+7
int n,r,p,top,num,cnt,col,ans;
int money[maxn],h[maxn*10],de[maxn],st[maxn],dfn[maxn],low[maxn],co[maxn],minn[maxn];
bool vis[maxn];
struct Edge
{
    int to;
    int next;
}e[maxn*20];
void add(int u,int v)
{
    e[++cnt].to=v;
    e[cnt].next=h[u];
    h[u]=cnt;
}
void read()
{
    cin>>n>>p;
    for(int i=1;i<=n;i++)
    minn[i]=money[i]=INF;//初始化 
    for(int i=1;i<=p;i++)
    {
        int x,y;
        cin>>x>>y;
        money[x]=y;
    }
    cin>>r;
    for(int i=1;i<=r;i++)
    {
        int x,y;
        cin>>x>>y;
        add(x,y);
    }
}
void Tarjan(int u)
{
    dfn[u]=low[u]=++num;
    st[++top]=u;
    vis[u]=1;
    for(int i=h[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(vis[v])
        {
            low[u]=min(low[u],dfn[v]);
        }
    }
    if(dfn[u]==low[u])
    {
        col++;
        while(st[top+1]!=u)
        {
            co[st[top]]=col;
            vis[st[top]]=0;
            minn[col]=min(minn[col],money[st[top]]);//计算每个强连通分量中的最小花费 
            top--;
        }
    }
}
int main()
{
    read();
    for(int i=1;i<=n;i++)
    if(!dfn[i]&&money[i]!=INF) Tarjan(i);//能被贿赂的人才可以缩点
    for(int i=1;i<=n;i++)
    if(!dfn[i])//如果dfn为0说明没有被控制 
    {
        cout<<"NO"<<endl<<i;
        return 0;
    }
    for(int i=1;i<=n;i++)//统计入度 
        for(int j=h[i];j;j=e[j].next)
            if(co[i]!=co[e[j].to]) de[co[e[j].to]]++;
    for(int i=1;i<=col;i++)//如果入度为0 即是一条链 
    if(!de[i]) ans+=minn[i];
    cout<<"YES"<<endl<<ans;
}
View Code

 

posted @ 2018-09-26 19:02  Nanchtiy  阅读(191)  评论(0编辑  收藏  举报