题目描述

由于外国间谍的大量渗入,国家安全正处于高度的危机之中。如果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:

3

2

1 10

2 100

2

1 3

2 3

输出样例#1:

YES

110

输入样例#2:

4

2

1 100

4 200

2

1 2

3 4

输出样例#2:

NO

3

说明

懒得多说直接上代码了。

#include<bits/stdc++.h>
using namespace std;
inline int read()
{
int x=0; char c=getchar();
while(!isdigit(c)) c=getchar();
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
return x;
}
int n,p,r,pat,top,tim,ans;
//pat表示边数,part表示强连通分量数,top表示栈高,tim表示时间戳
int mon[3100];
//money
int blg[3100],fa[3100];
//belong、father(其实两者本质是一样的,关于father等会儿会讲)
int dfn[3100],low[3100];
//深度优先(英文)、lowest(应该是吧)
int stk[3100],head[3100];
//stack(栈)、head是邻接链表的头(其实我觉得更像是尾)
bool instk[3100];
//instack表示是否在栈里面
struct tpat
{
int v,next;
}edge[8100]; void add(int u,int v)
{
edge[pat].next=head[u];
edge[pat].v=v;
head[u]=pat++;
} //邻接表存边( 比向量vector的push_back()要快 ) void tarjan(int u) //tarjan缩点不详解,自行百度
{
dfn[u]=low[u]=++tim;
instk[u]=true; stk[++top]=u;
for(int i=head[u];i!=-1;i=edge[i].next) //遍历点u的邻接表
{
int v=edge[i].v;
if(!dfn[v])
tarjan(v),low[u]=min(low[u] , low[v]);
else if(instk[v]) //这点很重要!被搜到过但不在栈内的话就不能操作
low[u]=min(low[u] , dfn[v]);
}
if(dfn[u]==low[u]) //low无变化代表u是一个强连通分量的出发点
{
int j;
do{
j=stk[top--];//从栈顶一直弹弹弹(弹走鱼尾纹),弹到u点(当前点)
mon[u]=min(mon[u] , mon[j]);
instk[j]=false; //出栈
blg[j]=u;
//注意这里就是把belong[j]赋值为u了,方便缩点后的操作
}while(j!=u); //弹到当前节点就退出
}
} void solve()
{
for(int i=1;i<=n;++i) //fa[i]都赋为本身
fa[i]=i;
for(int i=1;i<=n;++i)
for(int j=head[i];j!=-1;j=edge[j].next)
if(blg[i]!=blg[edge[j].v]) fa[blg[edge[j].v]]=blg[i];
//这里是不能把fa换成blg的,举个例子吧,
//如果只有三个点,然后有两条边使两个不同的点分别指向同一个点的话...
//想必你也猜到了,我也栽在这儿过~~~ _(:з」∠)_
for(int i=1;i<=n;++i)
{
if(blg[i]!=i || fa[i]!=i) //不是必须要付费的间谍就continue
continue;
if(mon[i]==0x3f3f3f3f) //如果说这个点无穷大就直接输出+退出
//话说我怎么觉得这里是有bug的来着?貌似我自己都能把自己hack掉...
//额...不过洛谷上是水过去了... _(:з」∠)_ 下文再放个图试试?
{
printf("NO\n%d\n",i);
return ; //输完直接退
}
ans+=mon[i]; //否则答案累加
}
printf("YES\n%d\n",ans);
} int main()
{
n=read();p=read();
memset(mon,0x3f,sizeof(mon));
memset(head,-1,sizeof(head));
for(int i=0;i<p;++i)
mon[read()]=read();
r=read();
for(int i=0;i<r;++i)
{ int u=read(),v=read(); add(u,v); } for(int i=1;i<=n;++i) //缩点
if(!dfn[i])
tarjan(i); solve(); //缩点完开始正式工作
return 0;
}

(看我注解写的多认真,你能忍心不点个赞吗? _ (:з」∠)_ )

然后我来说说我是怎么hack掉自己的程序的 … -_-|| (方便起见,假设没有一个间谍能被收买)

然后这就hack了?洛谷上还水过去了?心中一万匹草泥马在奔腾

然后呢?标程在哪里?

然我先想想…emmm好了上代码吧!

其实…只要把solve函数改成这样就好了:

#include<bits/stdc++.h>
using namespace std;
inline int read()
{
int x=0; char c=getchar();
while(!isdigit(c)) c=getchar();
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
return x;
}
int n,p,r,pat,top,tim,ans;
int mon[3100],mnode[3100];
//多开了一个mnode表示:如果该点是其所在的强连通分量的出发点,则该强连通分量中最小的点的编号
int blg[3100],fa[3100];
int dfn[3100],low[3100];
int stk[3100],head[3100];
bool instk[3100];
struct tpat
{
int v,next;
}edge[8100]; void add(int u,int v)
{
edge[pat].next=head[u];
edge[pat].v=v;
head[u]=pat++;
} void tarjan(int u)
{
dfn[u]=low[u]=++tim;
instk[u]=true; stk[++top]=u;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
if(!dfn[v])
tarjan(v),low[u]=min(low[u] , low[v]);
else if(instk[v])
low[u]=min(low[u] , dfn[v]);
}
if(dfn[u]==low[u]) //low无变化代表u是一个强连通分量的出发点
{
int j;
do{
j=stk[top--];//从栈顶一直弹弹弹(弹走鱼尾纹),弹到u点(当前点)
mon[u]=min(mon[u] , mon[j]);
instk[j]=false; //出栈
blg[j]=u;
if(mnode[j]==4000 || mnode[u]==4000)
//如果强连通分量中有人可以收买,则整个强连通分量中的人都可以被控制
mnode[u]=4000;
else mnode[u]=min(mnode[u] , mnode[j]);
}while(j!=u);
}
} void solve()
{
for(int i=1;i<=n;++i)
for(int j=head[i];j!=-1;j=edge[j].next)
if(blg[i]!=blg[edge[j].v])
fa[blg[edge[j].v]]=blg[i]; for(int i=1;i<=n;++i)
{
if(blg[i]==i)
mnode[fa[i]]=min(mnode[fa[i]] , mnode[i]);
//这里的意思是在某个强连通分量的出发点时将改点前驱的强连通分量的出发点取编号为min的操作
if(blg[i]!=i || fa[i]!=i)
continue;
if(mon[i]==0x3f3f3f3f)
{
printf("NO\n%d\n",mnode[i]); //然后这里输出就变成了当前点的最小编号
return ;
}
ans+=mon[i];
}
printf("YES\n%d\n",ans);
} int main()
{
n=read();p=read();
memset(mon,0x3f,sizeof(mon));
memset(head,-1,sizeof(head));
for(int i=0;i<p;++i)
mon[read()]=read();
r=read();
for(int i=0;i<r;++i)
{ int u=read(),v=read(); add(u,v); }
for(int i=1;i<=n;++i)
{ mnode[i]=fa[i]=i ; if(mon[i]!=0x3f3f3f3f) mnode[i]=4000; }
//可以收买的就直接为最大4000 for(int i=1;i<=n;++i)
if(!dfn[i])
tarjan(i); solve();
return 0;
}

珍惜无语,洛谷数据是真水啊,圣水!(再吐槽一波)

OK,本篇blog的正文到此结束,然后我是无力吐槽了,累得要死 _ (:з」∠) _

各位看官们下次见!

P1262 间谍网络 (tarjan缩点 水过去)的更多相关文章

  1. Luogu P2002 消息扩散&&P1262 间谍网络

    怕自己太久没写Tarjan了就会把这种神仙算法忘掉. 其实这种类型的图论题的套路还是比较简单且显然的. P2002 消息扩散 很显然的题目,因为在一个环(其实就是强连通分量)中的城市都只需要让其中一个 ...

  2. 洛谷——P1262 间谍网络

    P1262 间谍网络 题目描述 由于外国间谍的大量渗入,国家安全正处于高度的危机之中.如果A间谍手中掌握着关于B间谍的犯罪证据,则称A可以揭发B.有些间谍收受贿赂,只要给他们一定数量的美元,他们就愿意 ...

  3. 洛谷 P1262 间谍网络 —— 缩点

    题目:https://www.luogu.org/problemnew/show/P1262 首先,一个强连通分量里有一个点被控制则所有点都被控制,所以先 tarjan 缩点,记一下每个连通块中能被收 ...

  4. tyvj 1153 间谍网络 tarjan有向图强连通

    P1153 - 间谍网络 From ForeverBell    Normal (OI)总时限:13s    内存限制:128MB    代码长度限制:64KB 描述 Description 由于外国 ...

  5. P1262 间谍网络

    传送门 思路: ①在 Tarjan 的基础上加一个 belong 记录每个点属于哪个强连通分量. ②存图完成后,暴力地遍历全图,查找是否要间谍不愿受贿. inline void dfs(int u) ...

  6. luogu P1262 间谍网络

    嘟嘟嘟 建图还是很明显的. 接着分两种情况: 1.图中不存在环:那么只要收买那些入度为0的点.如果这些点有的不能收买.就不能控制所有间谍. 2.图中存在环,那么对于这些在环中的点,我们只要收买数额最少 ...

  7. 【luogu P1262 间谍网络】 题解

    题目链接:https://www.luogu.org/problemnew/show/P1262 注意: 1.缩点时计算出入度是在缩完点的图上用color计算.不要在原来的点上计算. 2.枚举出入度时 ...

  8. 洛谷 P1262 间谍网络==Codevs 4093 EZ的间谍网络

    4093 EZ的间谍网络 时间限制: 10 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题目描述 由于外国间谍的大量渗入,国家安全正处于高度的危机之中.如果A间谍手中掌握着关于B ...

  9. 洛谷 1262 间谍网络 Tarjan 图论

    洛谷 1262 图论 tarjan 并不感觉把这道题目放在图的遍历中很合适,虽然思路比较简单但是代码还是有点多的,, 将可收买的间谍的cost值设为它的价格,不可购买的设为inf,按照控制关系连图,T ...

随机推荐

  1. ruby数组操作方法汇总

    1.数组定义 arr1 = [] arr2 = Array.new arr3 = ['1','2','3'] 2.输出 print arr3,"\n" #123 puts arr3 ...

  2. `&nbsp;` `&emsp;` `&ensp;` `&thinsp;`

    字符实体 说明   这是我们使用最多的空格,也就是按下space键产生的空格.在HTML中,如果你用空格键产生此空格,空格是不会累加的(只算1个).要使用html实体表示才可累加.   占据的宽度正好 ...

  3. Oracle存储过程procedure in、out、in out 模式参数【不发布,纯转】

    Oracle存储过程procedure in.out.in out 模式参数 Oracle存储过程基本语法介绍 注意存过不会自动提交,需要在存过本身添加commit; rollback;等语句

  4. HDU 6362(求椭圆中矩形周长的期望 数学)

    题意是给定一个椭圆标准方程的a,b(椭圆的长半轴长和短半轴长),在[0,b]内取一个数,则过点(0,b)且平行于x轴的直线与椭圆交于两点,再将此两点关于x轴做对称点,顺次连接此四点构成矩形,求出这些矩 ...

  5. 绕不开的hadoop

    安装 jdk 1.8 # 官网下载可能比较慢,请自行搜索国内镜像源 wget http://download.oracle.com/otn-pub/java/jdk/8u191-b12/2787e4a ...

  6. [Android] Android RxBus 用法学习总结

    事件总线的好处在于方便组件之间的交互,RxBus不是一个库,而是使用RxJava实现事件总线的一种思想. rxbus和eventbus相比较: RxJava 主要做异步.网络的数据处理,强大之处就是对 ...

  7. Excel公式使用

    IF语句: 想要给F16自动求值,可以利用IF语句,如下: 语句: 同时,还需要设置B27的单元格格式为“常规”

  8. 百度编辑器 ueditor 会屏蔽过滤 body html head DOCTYPE ... 的解决办法

    百度编辑器很强,但有时候复制到html里时,会带有 body  html head 等标签,切到视图时,内容都不见了 是因为白名单 解决办法: 我测的是1.4.3版本 在 ueditor.config ...

  9. Dictionary与SortedDictionary

    Dictionary是无序的,如果想排序,需要使用SortDictionary. 下面是一个用法示例 //按照某个字段排序 public void SortByCardItem(string item ...

  10. Microsoft Windows .Reg File Dialog Box Message Spoofing 0day

    Microsoft Windows .Reg文件对话框消息欺骗 0day 概述 扩展名为.reg的文件是Windows注册表中使用的注册文件.这些文件可以包含hives.密钥和值..reg文件可以在文 ...