分析:
先对每个间谍dfs判是否有解。
有解的话,Tarjan SCC缩点,贪心地贿赂所有入度为0的强连通分量就可以了。
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
const int MAXN=3005;
const int MAXM=8005;
int n,p,m,ecnt,head[MAXN],q[MAXN],w[MAXN];
int dfn[MAXN],low[MAXN],tot,tot2;
int Stack[MAXN],Top;
int id[MAXN],deg[MAXN],cst[MAXN];
bool vis[MAXN],In[MAXN];
struct Edge{
int to,nxt;
}e[MAXM];
inline void add_edge(int bg,int ed){
ecnt++;
e[ecnt].to=ed;
e[ecnt].nxt=head[bg];
head[bg]=ecnt;
}
void dfs(int x){
vis[x]=1;
for(int i=head[x];i;i=e[i].nxt){
int ver=e[i].to;
if(vis[ver]) continue;
dfs(ver);
}
}
void tarjan(int x){
dfn[x]=low[x]=++tot;
Stack[++Top]=x;
In[x]=1;
for(int i=head[x];i;i=e[i].nxt){
int ver=e[i].to;
if(!dfn[ver]){
tarjan(ver);
low[x]=std::min(low[x],low[ver]);
}
else if(In[ver])
low[x]=std::min(low[x],dfn[ver]);
}
if(low[x]==dfn[x]){
tot2++;
while(Stack[Top+1]!=x){
id[Stack[Top]]=tot2;
In[Stack[Top]]=0;
Top--;
}
}
}
int main(){
memset(cst,0x3f,sizeof cst);
scanf("%d%d",&n,&p);
for(int i=1;i<=p;i++)
scanf("%d%d",&q[i],&w[i]);
scanf("%d",&m);
for(int i=1;i<=m;i++){
int u,v;scanf("%d%d",&u,&v);
add_edge(u,v);
}
for(int i=1;i<=p;i++)
if(!vis[q[i]]) dfs(q[i]);
for(int i=1;i<=n;i++)
if(!vis[i]){
printf("NO\n%d\n",i);
return 0;
}
printf("YES\n");
for(int i=1;i<=n;i++)
if(!dfn[i]) tarjan(i);
for(int i=1;i<=n;i++)
for(int j=head[i];j;j=e[j].nxt){
int ver=e[j].to;
if(id[i]==id[ver]) continue;
deg[id[ver]]++;
}
for(int i=1;i<=p;i++)
cst[id[q[i]]]=std::min(cst[id[q[i]]],w[i]);
int ans=0;
for(int i=1;i<=tot2;i++)
if(!deg[i]) ans+=cst[i];
printf("%d\n",ans);
return 0;
}