P1262 间谍网络

1、思路

阅读题目,发现有些间谍可以是被前面的点更新,也就是说,在一开始的时候,把能贿赂的人员从小到达排个序,再使用bfs算法,把他们能到达的人员的贿赂价钱设置为0。

有解的情况:

首先如果有环,我把环内的最少价钱的那一位买下,则整个环的间谍都被我买下。

首先把所有能被贿赂的根据bfs,依次把所有能到达的变为0

缩点之后,所有的都变为除了最小的那个,其他的都变为0,因此整个间谍网络只需要10就能买下。

但是对于如下情况

从小到大开始,依次是5,10,20,30。5能到达的点只有本身,不够,还要买下前面的环,而这个环10就能买下,因此如果有从X单向到Y,且X和Y都能买下,我们只需要买X。同理,尽管20比10更大,但是它还是需要买。否则无法买下所有的网络。因此,我们只需要买下缩点后入度为0的点就行。如果,如果入度为0的点不能被买下,那它就是无解。

有一个无法被遍历到,因此无解

无解的情况。

按能被贿赂的人员从小到大排序,依次处理每个能被贿赂的人员,如果能够被贿赂或者能够被更小的贿赂价钱到达,则打上一个标记,从小到大枚举所有人员,出现第一个标记则无解,输出该人员。

2、代码

cpp 复制代码
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 6100, M = 11100;
struct PT //从小到大存储叛徒的价钱 
{
	int id,val;
	bool operator < (const PT &t)const 
	{
		return val < t.val;
	}
}pt[N];

int h[N],e[M],ne[M],idx;
int stk[N],top,timestamp;
bool st[N];
int dfn[N],low[N],id[N],Size[N],cnt;
int n,p,r;
int Value[N];
bool st1[N];
int din[N];
void add(int a,int b)
{
	e[idx] = b;
	ne[idx] = h[a];
	h[a] = idx++;
}
void bfs(int x)// 将能到达的都置为0 
{

	if(st1[x]) return;
	st1[x] =true;
	int Q[N],tt = 1,hh = 0;
	Q[0] = x;
	while(hh!=tt)
	{
		int t = Q[hh++];
		for(int i = h[t];~i;i = ne[i])
		{
			int j = e[i];
			if(!st1[j])
			{
				st1[j] = true; 
				Q[tt++] = j;
				Value[j] = 0;
			}
		}
	}
}
void tarjan(int u) // 标准的tarjan算法 
{
	low[u] = dfn[u] = ++timestamp;
	stk[++top] = u;
	st[u] = true;
	for(int i = h[u];~i;i = ne[i])
	{
		int j = e[i];
		if(!dfn[j]) 
		{
			tarjan(j);
			low[u] = min(low[u],low[j]);
		}
		else if(st[j]) low[u] = min(low[u],dfn[j]);
	}
	if(low[u] == dfn[u])
	{
		++cnt;
		int y;
		do{
			y =  stk[top--];
			st[y] = false;
			id[y] = cnt;
			Size[cnt] += Value[y];
		}while(y!=u);
	}
}
int main()
{
	scanf("%d",&n);
	scanf("%d",&p);
	memset(h,-1,sizeof h);
	memset(Value,0x3f,sizeof Value);
	for(int i = 1;i<=p;i++)
	{
		scanf("%d%d",&pt[i].id,&pt[i].val);
		Value[pt[i].id] = pt[i].val;	
	}
	sort(pt+1,pt+p+1);
	
	scanf("%d",&r);
	for(int i = 1;i<=r;i++)
	{
		int a,b;
		scanf("%d%d",&a,&b);
		add(a,b);
	}
	for(int i = 1;i<=p;i++)
		bfs(pt[i].id);
			
	for(int i = 1;i<=n;i++)
	{
		if(!st1[i])
		{
			cout<<"NO"<<endl;
			cout<<i<<endl;
			return 0;
		}
	}
	for(int i = 1;i<=n;i++)if(!dfn[i])tarjan(i);
	for(int i = 1;i<=n;i++)
	{
		for(int j = h[i];~j;j = ne[j])
		{
			int k = e[j];
			int a = id[i],b = id[k];
			if(a!=b)din[b]++;
		}
	}
	int sum = 0;
	for(int i = cnt;i;i--)
	{
		 if(!din[i])sum += Size[i];
	}

	cout<<"YES"<<endl;
	cout<<sum<<endl;
	return 0;
} 
 
相关推荐
wx2004110217 小时前
树形dp总结
算法·深度优先·图论
小冉在学习2 天前
day60 图论章节刷题Part10(Floyd 算法、A * 算法)
算法·图论
XXXJessie2 天前
acwing算法基础03-递归,枚举
算法·深度优先·图论
chan_lay3 天前
图论导引 - 第三章 第三节:哈密顿图 - 11/11
图论
汉克老师4 天前
GESP4级考试语法知识(贪心算法(二))
开发语言·数据结构·c++·算法·贪心算法·图论·1024程序员节
yangmc044 天前
二维前缀和 子矩阵的和
c语言·数据结构·c++·git·算法·矩阵·图论
5pace4 天前
GNN系统学习:简单图论、环境配置、PyG中图与图数据集的表示和使用
学习·图论
chan_lay4 天前
图论导引 - 第三章 第二节:欧拉图 - 11/10
图论
patrickpdx5 天前
【图论】图的C++实现代码
c++·图论
chan_lay5 天前
图论导引 - 第二章 - 11/08
图论