- P1262 间谍网络
- 题意:
- 由于外国间谍的大量渗入,国家安全正处于高度的危机之中。如果A间谍手中掌握着关于B间谍的犯罪证据,则称A可以揭发B。有些间谍收受贿赂,只要给他们一定数量的美元,他们就愿意交出手中掌握的全部情报。所以,如果我们能够收买一些间谍的话,我们就可能控制间谍网中的每一分子。因为一旦我们逮捕了一个间谍,他手中掌握的情报都将归我们所有,这样就有可能逮捕新的间谍,掌握新的情报。
- 我们的反间谍机关提供了一份资料,包括所有已知的受贿的间谍,以及他们愿意收受的具体数额。同时我们还知道哪些间谍手中具体掌握了哪些间谍的资料。假设总共有n个间谍(n不超过3000),每个间谍分别用1到3000的整数来标识。
- 请根据这份资料,判断我们是否有可能控制全部的间谍,如果可以,求出我们所需要支付的最少资金。否则,输出不能被控制的一个间谍。
- 思路:缩点跑一下,这个连通块里面的只要一个能收买就都可以被逮捕,所以求一下缩点后的图 每个超级点需要收买的prize
- 缩完点后也不需要全都收买,只要入度为0的点都能够被收买就可以了,即是解也是最优解,topo检查一遍即可
-
#include<bits/stdc++.h> using namespace std; #define inf 0x3f3f3f3f #define maxn 8888 vector<int>g[maxn]; int w[maxn],n,p,r,a,b,color[maxn]; int low[maxn],dfn[maxn],pri[maxn]; int stk[maxn],tot,top,id,in[maxn]; bool instk[maxn]; void tarjan(int u) { int v; low[u]=dfn[u]=++tot; stk[++top]=u; instk[u]=1; for(int j=0; j<g[u].size(); j++) { v=g[u][j]; if(!dfn[v]) { tarjan(v); low[u]=min(low[v],low[u]); } else if(instk[v]) low[u]=min(low[u],dfn[v]); } if(low[u]==dfn[u]) { ++id; do { v=stk[top--]; color[v]=id; instk[v]=0; } while(v!=u); } } void topo() { int ans=0; for(int i=1; i<=id; i++) if(in[i]==0) { if(pri[i]==inf) { printf("NO\n"); for(int q=1; q<=n; q++) if(color[q]==i) { printf("%d\n",q); return ; } } ans+=pri[i]; } printf("YES\n%d\n",ans); } int main() { memset(w,inf,sizeof(w)); memset(pri,inf,sizeof(pri)); scanf("%d%d",&n,&p); for(int i=0; i<p; i++) { scanf("%d%d",&a,&b); w[a]=b; } scanf("%d",&r); while(r--) { scanf("%d%d",&a,&b); g[a].push_back(b); } for(int i=1; i<=n; i++) if(!dfn[i])tarjan(i); for(int i=1; i<=n; i++) if(w[i]!=inf)pri[color[i]]=min(pri[color[i]],w[i]); for(int i=1; i<=n; i++) for(int j=0; j<g[i].size(); j++) if(color[i]!=color[g[i][j]]) in[color[g[i][j]]]++; topo(); return 0; }
P1262 间谍网络-topo-tarjan
最新推荐文章于 2022-09-23 15:25:35 发布