zoukankan      html  css  js  c++  java
  • 洛谷P1262 间谍网络[强连通分量 BFS]

    题目描述

    由于外国间谍的大量渗入,国家安全正处于高度的危机之中。如果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,并在第二行输出不能控制的间谍中,编号最小的间谍编号。

    输入输出样例

    输入样例#1:
    【样例1】
    3
    2
    1 10
    2 100
    2
    1 3
    2 3
    【样例2】
    4
    2
    1 100
    4 200
    2
    1 2
    3 4
    输出样例#1:
    【样例1】
    YES
    110
    【样例2】
    NO
    3

    很明显的tarjan求scc,然后选择每个入度为0的scc里贿金最小的间谍
    判断有无解当然可以求完scc后新建图dfs,也可以先把所有可以贿赂的间谍入队BFS一遍
    //
    //  main.cpp
    //  luogu1262
    //
    //  Created by Candy on 11/11/2016.
    //  Copyright ? 2016 Candy. All rights reserved.
    //
    
    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    const int N=3005,M=8005,INF=1e9;
    inline int read(){
        char c=getchar();int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    int n,m,nn,u,v,w[N];
    struct edge{
        int v,ne;
    }e[N<<1];
    int h[N],cnt=0;
    inline void ins(int u,int v){
        cnt++;
        e[cnt].v=v;e[cnt].ne=h[u];h[u]=cnt;
    }
    struct person{
        int id,w;
    }p[N];
    int fw[N];
    int vis[N],q[N],head=1,tail=1;
    int bfs(){
        for(int i=1;i<=nn;i++) {q[tail++]=p[i].id;vis[p[i].id]=1;}
        while(head!=tail){
            int u=q[head++];
            for(int i=h[u];i;i=e[i].ne){
                int v=e[i].v;
                if(vis[v]) continue;
                vis[v]=1;
                q[tail++]=v;
            }
        }
        for(int i=1;i<=n;i++) if(!vis[i]) return i;
        return 0;
    }
    
    int dfn[N],low[N],belong[N],dfc,scc;
    int st[N],top;
    void dfs(int u){
        dfn[u]=low[u]=++dfc;
        st[++top]=u;
        for(int i=h[u];i;i=e[i].ne){
            int v=e[i].v;
            if(!dfn[v]){
                dfs(v);
                low[u]=min(low[u],low[v]);
            }else if(!belong[v])
                low[u]=min(low[u],dfn[v]);
        }
        if(dfn[u]==low[u]){
            scc++;
            while(true){
                int x=st[top--];
                belong[x]=scc;
                if(x==u) break;
            }
        }
    }
    void SCC(){
        for(int i=1;i<=n;i++) if(!dfn[i]) dfs(i);
    }
    int mn[N],ind[N];
    int sol(){
        memset(mn,127,sizeof(mn));
        for(int i=1;i<=nn;i++){
            int x=p[i].id,w=p[i].w;
            mn[belong[x]]=min(mn[belong[x]],w);
        }
        for(int u=1;u<=n;u++)
            for(int i=h[u];i;i=e[i].ne){
                int v=e[i].v;
                if(belong[u]!=belong[v]) ind[belong[v]]++;
            }
        int ans=0;
        for(int i=1;i<=scc;i++) if(ind[i]==0) ans+=mn[i];
        return ans;
    }
    int main(){
        n=read();nn=read();
        for(int i=1;i<=nn;i++) p[i].id=read(),p[i].w=read();
        m=read();
        for(int i=1;i<=m;i++){u=read();v=read();ins(u,v);}
        
        int x=bfs();
        if(x){printf("NO
    %d",x);return 0;}
        
        SCC();
        printf("YES
    %d",sol());
        return 0;
    }
     
  • 相关阅读:
    01.网页学习阶段、整站分析、规划
    书签搬运
    如何判断两个链表相交及找到第一个相交点
    Windows平台使用git bash管理github中的工程
    二级指针的操作
    结构体的内存对齐
    大端和小端
    剑指Offer——面试题26:复杂链表的复制
    使用editcap命令将ERF格式转换为pcap格式
    如何在STL的map中使用结构体作为键值
  • 原文地址:https://www.cnblogs.com/candy99/p/6054103.html
Copyright © 2011-2022 走看看