zoukankan      html  css  js  c++  java
  • 洛谷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;
    }
  • 相关阅读:
    03-spring bean
    04-spring的依赖注入
    01-课程安排
    17-注解开发
    WIN10新机必要设置记录 for 3dsmax
    ps导出svg
    VS C# 共享项目
    在Maxscript中创建.Net类型
    C# 自定义索引
    C# ?
  • 原文地址:https://www.cnblogs.com/iloveysm/p/12234758.html
Copyright © 2011-2022 走看看