抓間諜(強連通)

cn是大帅哥886發表於2024-07-18
https://www.luogu.com.cn/problem/P1262
第5題 抓間諜 檢視測評資料資訊

由於外國間諜的大量滲入,國家安全正處於高度的危機之中。如果 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

輸出:

YES

110

樣例解釋

縮點
1.有環:環中間諜賄賂最小值
2.入度為0:必須賄賂
無法賄賂:“NO”

#include <bits/stdc++.h>
using namespace std;
const int N=160005, MAX=1e9+5;

int n, m, p, u1, v1, x, money, t[N];
int dfn[N], low[N], idx=0, cnt=0, id[N], rd[N], Minid[N], Minmo[N], Aans=0, Bans;
stack<int> st;
vector<int> a[N];
void dfs(int u)
{
	dfn[u]=low[u]=++idx;
	st.push(u);
	
	for (int i=0; i<a[u].size(); i++)
	{
		int v=a[u][i];
		if (!dfn[v])
		{
			dfs(v);
			low[u]=min(low[u], low[v]);
		}
		else if (!id[v]) low[u]=min(low[u], dfn[v]);
	}
	
	if (dfn[u]==low[u])
	{
		cnt++;
		while (st.top()!=u)
		{
			id[st.top()]=cnt;
			Minmo[cnt]=min(Minmo[cnt], t[st.top()]);
			Minid[cnt]=min(Minid[cnt], st.top());
			st.pop();
		}
		id[st.top()]=cnt;
		Minmo[cnt]=min(Minmo[cnt], t[st.top()]);
		Minid[cnt]=min(Minid[cnt], st.top());
		st.pop();
	}
}
int main()
{
	for (int i=0; i<N-5; i++) t[i]=Minid[i]=Minmo[i]=MAX;
	
	scanf("%d%d", &n, &p);
	for (int i=1; i<=p; i++)
	{
		scanf("%d%d", &x, &money);
		t[x]=money;
	}
	scanf("%d", &m);
	for (int i=1; i<=m; i++)
	{
		scanf("%d%d", &u1, &v1);
		a[u1].push_back(v1);
	}
	
	for (int i=1; i<=n; i++)
		if (!dfn[i] && t[i]!=MAX) dfs(i);
	
	for (int i=1; i<=n; i++)
		if (!dfn[i])
		{
			printf("NO\n%d", i);
			return 0;
		}
	
	for (int u=1; u<=n; u++)
		for (int j=0; j<a[u].size(); j++)
		{
			int v=a[u][j];
			if (id[u]!=id[v]) rd[id[v]]++;
		}
	
	for (int i=1; i<=cnt; i++)
	{
		if (rd[i]!=0) continue;
		Bans+=Minmo[i];
	} 
	
	printf("YES\n%d", Bans);
	return 0;
}

  

相關文章