P1262 间谍网络

链接

https://www.luogu.com.cn/problem/P1262

思路

主要就是强连通分量,缩点。
首先判断根据现有的入口能不能达到所有的点[通过dfs],能就进行下一步。
接着使用模板tarjan缩点,给每个点编一个sccno。

接下来是新东西:怎么获得最小代价?由于必然能得到最后的代价,并且最后缩点完必然是“链”。
那么

1.获得每个sccno里最小的代价

2.获得入度为0的sccno(也就是链条的起始端)的代价。
这里怎么获得入度为0呢?再写一个dfs

void dfsFinal(int u)
{
	if (vis[u])return;
	vis[u] = true;
	for (int v : G[u])
	{
		if (sccno[u] != sccno[v])
			rd[sccno[v]]++;
		dfsFinal(v);
	}
}

3.计算答案:

for (int i = 1; i <= cnt;i++)
	{
		if (rd[i] == 0)
			if(sccnoMin[i]!=INF)
				ans += sccnoMin[i];
	}

代码

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define tin long long
#define itn long long
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
void solve();

const int N = 3e3 + 10;
const int INF = LLONG_MAX;
int n, p, r;
int val[N];
vector<int>G[N];
vector<int>beginer;
bool vis[N];
int cnter;
int sccnoMin[N];
void read()
{
	cin >> n;
	for (int i = 0; i < N; i++)val[i] = sccnoMin[i]= INF;
	cin >> p;
	for (int i = 1; i <= p; i++)
	{
		int x, v;
		cin >> x >> v;
		val[x] = v;
		beginer.push_back(x);
	}
	cin >> r;
	for (int i = 1; i <= r; i++)
	{
		int a, b; cin >> a >> b;
		G[a].push_back(b);
	}
}
void dfsINIT(int x)
{
	if (vis[x])return;
	vis[x] = true;
	cnter++;
	for (int xx : G[x])dfsINIT(xx);
}

int cnt;
int low[N], num[N], dfn;
int sccno[N];
int rd[N];
stack<int>st;
void dfs(int u)
{
	st.push(u);
	low[u] = num[u] = ++dfn;
	for (int i = 0; i < G[u].size(); i++)
	{
		int v = G[u][i];
		if (!num[v])
		{
			dfs(v);
			low[u] = min(low[v], low[u]);

		}
		else if (!sccno[v])
			low[u] = min(low[u], num[v]);
	}
	if (low[u] == num[u])
	{
		cnt++;
		while (1)
		{
			int v = st.top(); st.pop();
			sccno[v] = cnt;
			if (u == v)break;
			
		}
	}
}
void Tarjan()
{
	cnt = dfn = 0;
	memset(sccno, 0, sizeof(sccno));
	memset(num, 0, sizeof(num));
	memset(low, 0, sizeof(low));
	for (int i = 1; i <= n; i++)
		if (!num[i])
			dfs(i);
}

void dfsFinal(int u)
{
	if (vis[u])return;
	vis[u] = true;
	for (int v : G[u])
	{
		if (sccno[u] != sccno[v])
			rd[sccno[v]]++;
		dfsFinal(v);
	}
}

void solve()
{
	read();

	for (int x : beginer)dfsINIT(x);
	if(cnter!=n)
		for(int i=1;i<=n;i++)
			if (!vis[i])
			{
				cout << "NO\n" << i;
				return;
			}
	Tarjan();
	//获取每个sccno里面的最小值
	for (itn i = 1; i <= n; i++)
	{
		sccnoMin[sccno[i]] = min(sccnoMin[sccno[i]], val[i]);
	}
	memset(vis, 0, sizeof(vis));
	//获取每个sccno对应 的入度,取入度为0的
	for (int i = 1; i <= n; i++)
		if (!vis[i])
			dfsFinal(i);
	int ans = 0;
	for (int i = 1; i <= cnt;i++)
	{
		if (rd[i] == 0)
			if(sccnoMin[i]!=INF)
				ans += sccnoMin[i];
	}
	cout << "YES\n" << ans;
}




signed main()
{
	IOS;

	solve();
	return 0;
}


posted @ 2025-05-29 15:32  WHUStar  阅读(13)  评论(0)    收藏  举报