1 条题解
-
0
自动搬运
来自洛谷,原作者为

Danny_boodman
**搬运于
2025-08-24 21:23:03,当前版本为作者最后更新于2018-05-10 19:16:26,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
可以看出此题有两种情况:
一是有的罪犯既不能贿赂他也没有罪犯能揭发他,那么此题无解,我们在遍历时打上标记,然后从小到大枚举,只要遇见没有标记的就输出然后退出即可
二是所有的罪犯都能直接或间接地被能贿赂的罪犯揭发。很明显,也有两种情况,一是没有环,那么资金就是贿赂那个没有入度的罪犯,二是有环,那么资金就是那个环里罪犯所需资金最小的。我们想,如果我们把环里的罪犯缩成一个点,那么全都是前者的情况了
至于如何缩点欢迎来看我的博客
#include<iostream> #include<stdio.h> #include<cstring> using namespace std; struct ss{ int next,to; };ss data[200010]; const int inf=1e9+7; int n,q,timeclock,p,top,cnt,ans,r; int dfn[200010],low[200010],stack[200010],instack[200010],next[200010],head[200010]; int belong[200010],money[200010],sum[200010],size[200010],rd[200010]; void add(int a,int b) { data[++p].next=head[a]; data[p].to=b; head[a]=p; } void tarjan(int a) //标准的tarjan代码 { dfn[a]=low[a]=++timeclock; instack[a]=1; stack[++top]=a; for(int i=head[a];i;i=data[i].next) { int v=data[i].to; if(!dfn[v]) { tarjan(v); low[a]=min(low[a],low[v]); } else if(instack[v]) low[a]=min(low[a],dfn[v]); } if(dfn[a]==low[a]) { cnt++; while(stack[top+1]!=a) { belong[stack[top]]=cnt; instack[stack[top]]=0; size[cnt]++; sum[cnt]=min(sum[cnt],money[stack[top]]); top--; } } } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) money[i]=1e9+7; //记得赋初值哦 for(int i=1;i<=n;i++) sum[i]=1e9; scanf("%d",&q); for(int i=1;i<=q;i++) { int u,mo; scanf("%d%d",&u,&mo); money[u]=mo; } scanf("%d",&r); for(int i=1;i<=r;i++) { int u,v; scanf("%d%d",&u,&v); add(u,v); } for(int i=1;i<=n;i++) if(!dfn[i]&&money[i]!=inf) //如果他能够被贿赂就以他为起点找环 tarjan(i); for(int i=1;i<=n;i++) //在这里我们用dfn数组来判断它是否被遍历过 if(!dfn[i]) { printf("NO\n"); printf("%d\n",i); return 0; } for(int i=1;i<=n;i++) for(int j=head[i];j;j=data[j].next) if(belong[i]!=belong[data[j].to]) { rd[belong[data[j].to]]++; //记录入度 } printf("YES\n"); for(int i=1;i<=cnt;i++) { if(!rd[i]) { ans+=sum[i]; } } printf("%d\n",ans); return 0; }
- 1
信息
- ID
- 262
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 4
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者