P1262 间谍网络 (tarjan缩点 水过去)
题目描述
由于外国间谍的大量渗入,国家安全正处于高度的危机之中。如果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缩点 水过去)的更多相关文章
- Luogu P2002 消息扩散&&P1262 间谍网络
怕自己太久没写Tarjan了就会把这种神仙算法忘掉. 其实这种类型的图论题的套路还是比较简单且显然的. P2002 消息扩散 很显然的题目,因为在一个环(其实就是强连通分量)中的城市都只需要让其中一个 ...
- 洛谷——P1262 间谍网络
P1262 间谍网络 题目描述 由于外国间谍的大量渗入,国家安全正处于高度的危机之中.如果A间谍手中掌握着关于B间谍的犯罪证据,则称A可以揭发B.有些间谍收受贿赂,只要给他们一定数量的美元,他们就愿意 ...
- 洛谷 P1262 间谍网络 —— 缩点
题目:https://www.luogu.org/problemnew/show/P1262 首先,一个强连通分量里有一个点被控制则所有点都被控制,所以先 tarjan 缩点,记一下每个连通块中能被收 ...
- tyvj 1153 间谍网络 tarjan有向图强连通
P1153 - 间谍网络 From ForeverBell Normal (OI)总时限:13s 内存限制:128MB 代码长度限制:64KB 描述 Description 由于外国 ...
- P1262 间谍网络
传送门 思路: ①在 Tarjan 的基础上加一个 belong 记录每个点属于哪个强连通分量. ②存图完成后,暴力地遍历全图,查找是否要间谍不愿受贿. inline void dfs(int u) ...
- luogu P1262 间谍网络
嘟嘟嘟 建图还是很明显的. 接着分两种情况: 1.图中不存在环:那么只要收买那些入度为0的点.如果这些点有的不能收买.就不能控制所有间谍. 2.图中存在环,那么对于这些在环中的点,我们只要收买数额最少 ...
- 【luogu P1262 间谍网络】 题解
题目链接:https://www.luogu.org/problemnew/show/P1262 注意: 1.缩点时计算出入度是在缩完点的图上用color计算.不要在原来的点上计算. 2.枚举出入度时 ...
- 洛谷 P1262 间谍网络==Codevs 4093 EZ的间谍网络
4093 EZ的间谍网络 时间限制: 10 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题目描述 由于外国间谍的大量渗入,国家安全正处于高度的危机之中.如果A间谍手中掌握着关于B ...
- 洛谷 1262 间谍网络 Tarjan 图论
洛谷 1262 图论 tarjan 并不感觉把这道题目放在图的遍历中很合适,虽然思路比较简单但是代码还是有点多的,, 将可收买的间谍的cost值设为它的价格,不可购买的设为inf,按照控制关系连图,T ...
随机推荐
- mysql批量替换数据
如题,项目域名迁移,导致原来商城的商品图片无法查看,地址错误. 怎么办?修改数据库图片路径呗!什么几千行呐,开玩笑.这个任务没人接,只有我干咯! 怎么也得不少时间吧,好吧半天,这是上面的要求. 有聪明 ...
- Web前端框架与移动应用开发第八章
Web前端框架与移动应用开发:制作58招聘专题页 1.html代码: <!DOCTYPE html><html><head> <meta charset=&q ...
- 【leetcode-69】 x 的平方根
(主要是越界问题) 实现 int sqrt(int x) 函数. 计算并返回 x 的平方根,其中 x 是非负整数. 由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去. 示例 1: 输入: 4 ...
- vue filter过滤器简单应用
vue中过滤器,用于一些常见的文本格式化,用 | 来操作. 过滤器可以用在两个地方: 1.在{{}}双花括号中插入值 2.v-bind表达式中使用 <!-- 在双花括号中 --> {{ m ...
- vue项目中引用jquery
1.使用npm安装 npm i jquery --S //jquery要小写 2.在package.json文件dependencies里面加入jq 3.在build文件夹的webpack.base. ...
- JavaScript 实现一个简单的MVVM前端框架(ES6语法)
前言 随着前端各大框架的崛起,为我们平时的开发带来了相当的便利,我们不能一直停留在应用层面,今天就自己动手实现一个乞丐版的MVVM小框架 完整代码github地址 效果 html代码 <div ...
- 数据结构Java实现01----线性表与顺序表
一.线性结构: 如果一个数据元素序列满足: (1)除第一个和最后一个数据元素外,每个数据元素只有一个前驱数据元素和一个后继数据元素: (2)第一个数据元素没有前驱数据元素: (3)最后一个数据元素没有 ...
- shell 命令使用笔记
1.提取字符串中以.ddd结尾的ddd值 result=$(echo "chip86.500" | grep -Eo '\.[0-9]{1,}' | grep -Eo '[0-9] ...
- 三十四、Linux 进程与信号——信号特点、信号集和信号屏蔽函数
34.1 信号特点 信号的发生是随机的,但信号在何种条件下发生是可预测的 进程杠开始启动时,所有信号的处理方式要么默认,要么忽略:忽略是 SIGUSR1 和 SIGUSR2 两个信号,其他都采取默认方 ...
- MVC异步AJAX的三种方法(JQuery的Get方法、JQuery的Post方法和微软自带的异步方法)
异步是我们在网站开发过程中必不可少的方法,MVC框架的异步方法也有很多,这里介绍三种方法: 一.JQuery的Get方法 view @{ Layout = null; } <!DOCTYPE h ...