洛谷P1262 间谍网络

 

题目描述

由于外国间谍的大量渗入,国家安全正处于高度的危机之中。如果A间谍手中掌握着关于B间谍的犯罪证据,则称A可以揭发B。有些间谍收受贿赂,只要给他们一定数量的美元,他们就愿意交出手中掌握的全部情报。所以,如果我们能够收买一些间谍的话,我们就可能控制间谍网中的每一分子。因为一旦我们逮捕了一个间谍,他手中掌握的情报都将归我们所有,这样就有可能逮捕新的间谍,掌握新的情报。

我们的反间谍机关提供了一份资料,包括所有已知的受贿的间谍,以及他们愿意收受的具体数额。同时我们还知道哪些间谍手中具体掌握了哪些间谍的资料。假设总共有n个间谍(n不超过3000),每个间谍分别用1到3000的整数来标识。

请根据这份资料,判断我们是否有可能控制全部的间谍,如果可以,求出我们所需要支付的最少资金。否则,输出不能被控制的一个间谍。

输入格式

第一行只有一个整数n。

第二行是整数p。表示愿意被收买的人数,1≤p≤n。

接下来的p行,每行有两个整数,第一个数是一个愿意被收买的间谍的编号,第二个数表示他将会被收买的数额。这个数额不超过20000。

紧跟着一行只有一个整数r,1≤r≤8000。然后r行,每行两个正整数,表示数对(A, B),A间谍掌握B间谍的证据。

输出格式

如果可以控制所有间谍,第一行输出YES,并在第二行输出所需要支付的贿金最小值。否则输出NO,并在第二行输出不能控制的间谍中,编号最小的间谍编号。

stdin:

3
2
1 10
2 100
2
1 3
2 3

stdout:

YES
110

问题分析:将所有间谍的关系看作一个有向图,这样的话,入度为零的点必须买,因为没有其他人可以揭发此人.其次,若是有间谍为孤立点,则此情况下肯定为no,我们可以在存的时候记录一下各个间谍的

出现情况。对于可以被收买的人,我们以他为起点找环,取该环中可被收买的人的最小价,最后取和。

#include<bits/stdc++.h>
using namespace std;
int head[10010];
int scc[10010],size[10010];
int pm[10010],log1[10010];
int sum[10010];
int dfn[10010],low[10010];
int rd[10010];
bool f[10010];
int s[10010];
int top;
int cnt,cnt1;
struct node{
int to;
int next;
int w;
}e[10000];
int n,p,r;
int t;
int ans;
void add(int x,int y)
{
    e[++cnt].to=y;
    e[cnt].next=head[x];
    head[x]=cnt;
}
void tarjan(int k)
{
    low[k]=dfn[k]=++t;
    f[k]=true;
    s[++top]=k;
    for(int i=head[k];i;i=e[i].next)
    {
        int v=e[i].to;
        if(!dfn[v])
        {
            tarjan(v);
            low[k]=min(low[k],low[v]);
        }
        else
        {
            if(f[v])
            low[k]=min(low[k],dfn[v]);
        }
    }
    if(low[k]==dfn[k])
    {
        cnt1++;
        while(s[top+1]!=k)
        {
            int t=s[top];
            scc[t]=cnt1;//该点入该环
            f[t]=false;
            size[cnt1]++;//记录当前环的大小
            sum[cnt1]=min(pm[t],sum[cnt1]);//找环中最便宜的
            top--;//退栈
        }
    }
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    pm[i]=1e9+7;
    for(int i=1;i<=n;i++)
    sum[i]=1e9;
    cin>>p;
    while(p--)
    {
        int q;
        int m;
        cin>>q>>m;
        pm[q]=m;
        log1[q]=1;
    }
    cin>>r;
    while(r--)
    {
        int x,y;
        cin>>x>>y;
        add(x,y);
        if(pm[x]!=0)
            log1[y]=1;
        if(pm[y]!=0)
        log1[y]=1;//这里记录谁不在关系网中出现
    }
    for(int i=1;i<=n;i++)
    {
        if(!dfn[i]&&pm[i]!=1e9+7)//如果能被收买,跑tarjan
            tarjan(i);
    }
    for(int i=1;i<=n;i++)
        if(log1[i]==0)
        {cout<<"NO"<<endl;
            cout<<i;
        return 0;
        }
    for(int i=1;i<=n;i++)
        for(int j=head[i];j;j=e[j].next)
    {
        int v=e[j].to;
        if(scc[i]!=scc[v])
            rd[scc[v]]++;//记录入度
    }
     for(int i=1;i<=cnt1;i++)
     {
         if(!rd[i])
            ans+=sum[i];
     }
     cout<<"YES"<<endl;
     cout<<ans;
    return 0;
}

 

 

 

posted @ 2020-01-26 20:33  remarkableboy  阅读(247)  评论(0编辑  收藏  举报