描述 由于外国间谍的大量渗入,国家安全正处于高度危机之中。如果 A 间谍手中掌握着关于 B 间谍的犯罪证据,则称 A 可以揭发 B
。有些间谍接受贿赂,只要给他们一定数量的美元,他们就愿意交出手中掌握的全部情报。所以,如果我们能够收买一些间谍的话,我们就可能控制间谍网中的每一分子。因为一旦我们逮捕了一个间谍,他手中掌握的情报都将归我们所有,这样就有可能逮捕新的间谍,掌握新的情报。我们的反间谍机关提供了一份资料,包括所有已知的受贿的间谍,以及他们愿意收受的具体数额。同时我们还知道哪些间谍手中具体掌握了哪些间谍的资料。假设总共有
nn 个间谍,每个间谍分别用 11 到30003000 的整数来标识。请根据这份资料,判断我们是否可能控制全部的间谍,如果可以,求出我们所需要支付的最少资金。否则,输出不能被控制的一个间谍。
输入 第一行只有一个整数 nn。第二行是整数pp。表示愿意被收买的人数。
接下来的 pp 行,每行有两个整数,第一个数是一个愿意被收买的间谍的编号,第二个数表示他将会被收买的数额。
紧跟着一行只有一个整数 rr。然后 rr 行,每行两个正整数,表示数对 (A,B)(A,B),AA 间谍掌握 BB 间谍的证据。
输出
如果可以控制所有间谍,第一行输出YES,并在第二行输出所需要支付的贿金最小值。否则输出NO,并在第二行输出不能控制的间谍中,编号最小的间谍编号。
样例输入
2
1
2 512
2
1 2
2 1
样例输出
YES
512
提示 1≤n≤3000,1≤p≤n,1≤r≤80001≤n≤3000,1≤p≤n,1≤r≤8000,
每个收买的费用为非负数且不超过2000020000。
分析:
SCC,这类关系传递的题先缩点,缩点时记录每个新点中的最小花费和最小编号,那么我们能控制整个网络,当且仅当可以贿赂所有入度为0的点,因为没有任何人有他们的情报
最小花费即所有入度为0的点的最小花费和,而最小编号不一定在入度为0的点中,比如2->1->3 仅3接受贿赂,所以此时我们要统计入度为0的点及其后继点中入度为1的点的最小编号
此时还有一个问题:2->3 3->1 4->1 此时1号点的入度为2,但也要统计,如何实现?很简单,从一个入度为0的点搜索到第一个入读不为1的点时把这个点的入度-1就行了
代码:(仍然是CSDN的锅,请自行复制)
#include<bits/stdc++.h>
const int INF=0x3f;
using namespace std;
const int N=100005,M=200005;
int n,m;
int a[N],in[N]={0},nExt[N]={0};
int ans=1000000000,flag=1,total=0;
int fro[N],sta[N],insta[N]={0},top=0,tot=0,vis[M],head[M],nxt[M],id[N],sign=0,scc=0,low[N],dfn[N],mon[N],minn[N];
inline void add(int x,int y){fro[++tot]=x;vis[tot]=y,nxt[tot]=head[x];head[x]=tot;}
void tarjan(int v){
low[v]=dfn[v]=++sign;
sta[++top]=v;insta[v]=1;
for(int i=head[v];i;i=nxt[i]){
int y=vis[i];
if(!dfn[y]) {tarjan(y);low[v]=min(low[y],low[v]);}
else if(insta[y]) low[v]=min(low[v],dfn[y]);
}
if(low[v]==dfn[v]){
++scc;int i=sta[top];
while(i!=v) {mon[scc]=min(mon[scc],a[i]);minn[scc]=min(minn[scc],i);insta[i]=0;id[i]=scc;i=sta[--top];}
insta[v]=0;id[v]=scc;top--;mon[scc]=min(mon[scc],a[v]);minn[scc]=min(minn[scc],v);
}
}
void get_ans(int v){
if(mon[v]==1000000000){
ans=min(ans,minn[v]);v=nExt[v];
flag=0;
while(in[v]==1){
ans=min(ans,minn[v]);
v=nExt[v];
}
in[v]--;
}
else total+=mon[v];
}
void sd(){
for(int i=1;i<=m;i++)
{
if(id[fro[i]]!=id[vis[i]]){
nExt[id[fro[i]]]=id[vis[i]];
in[id[vis[i]]]++;
}
}
for(int i=1;i<=scc;i++)
if(in[i]==0) get_ans(i);
}
int main(){
cin>>n;
int p;
cin>>p;
for(int i=1;i<=n;i++) a[i]=1000000000,mon[i]=1000000000,minn[i]=1000000000;
while(p--){
int x,monn;
scanf("%d%d",&x,&monn);
a[x]=monn;
}
cin>>m;
for(int i=1;i<=m;i++){
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
}
for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
sd();
if(!flag) cout<<"NO"<<endl<<ans;
else cout<<"YES"<<endl<<total;
return 0;
}