【基础练习】【强连通tarjan】codevs4093 EZ的间谍网络题解

题目描述 Description

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

  我们的神通广大的YJY获得了一份资料,色括所有已知的受贿的间谍,以及他们愿意收受的具体数额。同时我们还知道哪些间谍手中具体掌握了哪些间谍的资料。假设总共有n个间谍(n不超过3000),每个间谍分别用13000的整数来标识。

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


输入描述 Input Description

第一行只有一个整数n

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

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

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


输出描述 Output Description

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


样例输入 Sample Input

【样例1

3

2

1 10

2 100

2

1 3

2 3

【样例2

4

2

1 100

4 200

2

1 2

3 4

 


样例输出 Sample Output

【样例1

YES

110

 

【样例2

NO<a name="_GoBack"></a>

3


 


数据范围及提示 Data Size & Hint

各个测试点1s



友情提示:请先膜拜下万能的YJY再做呦^_^

对于每个环,环内任意一个元素可以揭发其他所有人 因此只需要把环缩成一点 这点的权值为环上点权值的最小值

如果遇到一条链,由于我们的目的是把所有的间谍都控制,因此必须控制链的起点元素。

在环缩点之后,凡是入度为0的点,要么是独立的点,要么是链的起始点;同时,所有需要被控制的点,即链的起始点和独立点,必然入度为0。因此只需统计入度为零的点权值和。

如果缩点后存在不能被控制的入度为0的点 则需要找出不能控制的点中最小的一个。因此我们在缩点时同时记录这个环中编号最小点,并将不能控制的点权值赋值为极大值。最后我们扫一遍求得编号最小的点即可。


这道题目即使是10s的时间鄙人还是狂T不止。最后试出数据,发现还是错在了低级错误上。遍历边的时候竟然写的是i=next[x]而不是i=next[i],因此i的值始终卡在一个值上,当然会死循环。

代码

//codevs4093 EZ的间谍网络 tarjan
//copyright by ametake
//task:首先缩点 并把点值赋值为最小代价 然后重构图统计入度 对入度为0的点求和 
#include
   
   
    
    
#include
    
    
     
     
#include
     
     
      
      
#include
      
      
       
       
using namespace std;

const int maxn=3000+10;
const int maxm=8000+10;

int n,p,r;
int hd[maxn],tt[maxm*2],nxt[maxm*2],et;
int money[maxn],fin[maxn];
int dfn[maxn],low[maxn],dep=0;
int inwhich[maxn],sta[maxn],stp=0;
bool ins[maxn],ok,ru[maxn][maxn];
int tot,ans,rudu[maxn],mip[maxn]; 

int read()
{
    int a=0;
    int f=1;
    char ch=getchar();
    while (ch>'9'||ch<'0')
    {
        if (ch=='-') f=-1;
        ch=getchar();
    }
    while (ch<='9'&&ch>='0')
    {
        a=a*10+ch-'0';
        ch=getchar();
    }
    a*=f;
    return a;
}

void add(int x,int y)
{
    et++;
    tt[et]=y;
    nxt[et]=hd[x];
    hd[x]=et;
}


void tarjan(int x)
{
    dfn[x]=low[x]=++dep;
    ins[x]=true;
    sta[++stp]=x;
    for (int i=hd[x];i!=0;i=nxt[i])
    {
        if (!dfn[tt[i]])
        {
            tarjan(tt[i]);
            low[x]=min(low[x],low[tt[i]]);
        }
        else if (ins[tt[i]])
        {
            low[x]=min(low[x],dfn[tt[i]]);
        }
    }
    if (dfn[x]==low[x])
    {
        int j;
        tot++;
        int minn=0x3f3f3f,mij=0x3f3f3f;
        do
        {
            j=sta[stp--];
            ins[j]=false;
            inwhich[j]=tot;
            mij=min(mij,j);
            if (money[j]
       
       
      
      
     
     
    
    
   
   

——槛菊愁烟兰泣露,罗幕轻寒,燕子双飞去


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值