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;
}

浙公网安备 33010602011771号