1 条题解

  • 0
    @ 2025-8-24 21:23:04

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar 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
    上传者