洛谷P1262-间谍网络 题解
1262-间谍网络-tarjan
有一些间谍可以被一定金钱收买,控制一个间谍就可以控制它掌握的所有间谍,以此递推下去。求最少用多少钱就可以控制所有间谍。如果不能输出-1。
首先从可以被掌控的间谍那里开始dfs,判断能不能覆盖所有点。若不能输出-1结束。
考虑没有环的情况,入度为0的间谍一定需要被收买,而且只需要收买所有入度为0的间谍就可以控制所有入度不为零的间谍。
如果有环,则需要先tarjan缩点,然后判断环的总入度,同理,只需要收买所有入度为0的点或环就可以控制全部。对于环,我们只需要收买环上的任意一个间谍即可,优先收买代价最小的,遍历环上的间谍即可。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=5e3+10;
stack<int> k1;
int sp[maxn],dfn[maxn],dfsnum,rd[maxn],dlow[maxn],dfstot;
bool visst[maxn];
bool vistot[maxn];
vector<int> yuan[maxn];
int zhi[maxn];
int n,p,r;
bool vis[maxn],can[maxn];
vector<int> ssp[maxn];
void dfs(int now){
vis[now]=1;
for(int i=0;i<yuan[now].size();i++){
int v=yuan[now][i];
if(!vis[v]) dfs(v);
}
}
void tarjan(int now){
dfn[now]=dlow[now]=++dfsnum;
k1.push(now);visst[now]=1;
for(int i=0;i<yuan[now].size();i++){
int v=yuan[now][i];
if(!dfn[v]){
tarjan(v);
dlow[now]=min(dlow[now],dlow[v]);
}
else if(visst[v]) dlow[now]=min(dlow[now],dfn[v]);
}
if(dlow[now]==dfn[now]){
dfstot++;
while(!k1.empty()){
int tmp=k1.top();
k1.pop();
sp[tmp]=dfstot;
visst[tmp]=0;
if(tmp==now) break;
}
}
}
int main(){
cin>>n>>p;
for(int i=1;i<=p;i++){
int a1,a2;cin>>a1>>a2;
zhi[a1]=a2;
can[a1]=1;
}
cin>>r;
for(int i=1;i<=r;i++){
int a1,a2;cin>>a1>>a2;
yuan[a1].push_back(a2);
}
for(int i=1;i<=n;i++){
if(can[i]) dfs(i);
}
for(int i=1;i<=n;i++){
if(!vis[i]){
cout<<"NO\n"<<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=0;j<yuan[i].size();j++){
int v=yuan[i][j];
if(sp[i]!=sp[v]) rd[sp[v]]++;
else continue;
}
}
for(int i=1;i<=n;i++) if(can[i]) ssp[sp[i]].push_back(i);
ll ans=0;
for(int i=1;i<=n;i++){
if(zhi[i]){
if(rd[sp[i]]==0&&!vistot[sp[i]]){
vistot[sp[i]]=1;
ll min1=inf;
for(int j=0;j<ssp[sp[i]].size();j++){
int v=ssp[sp[i]][j];
min1=min(min1,(ll)zhi[v]);
}
ans+=min1;
}
}
}
cout<<"YES\n"<<ans<<endl;
return 0;
}

浙公网安备 33010602011771号