zoukankan      html  css  js  c++  java
  • 洛谷 P1262 间谍网络 —— 缩点

    题目:https://www.luogu.org/problemnew/show/P1262

    首先,一个强连通分量里有一个点被控制则所有点都被控制,所以先 tarjan 缩点,记一下每个连通块中能被收买的人的最小价钱,和整个连通块的点的最小 id;

    然后如果有入度为0的点不能被收买,则输出 NO,找最小 id 时注意要找它指向的所有点,又不包括中间可以被收买的;

    否则就是 YES,花费就是入度为0的点的最小代价之和。

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int const xn=3005,xm=8005,inf=0x3f3f3f3f;
    int n,m,hd[xn],ct,to[xm],nxt[xm],fr[xm],dfn[xn],low[xn],tim,sta[xn],top;
    int deg[xn],col[xn],cr,hd2[xn],ct2,to2[xm],nxt2[xm],p,w[xn],ans,mn[xn],mi[xn];
    bool vis[xn];
    void add(int x,int y){to[++ct]=y; fr[ct]=x; nxt[ct]=hd[x]; hd[x]=ct;}
    void add2(int x,int y){to2[++ct2]=y; nxt2[ct2]=hd2[x]; hd2[x]=ct2;}
    int rd()
    {
        int ret=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();}
        while(ch>='0'&&ch<='9')ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar();
        return f?ret:-ret;
    }
    void tarjan(int x)
    {
        dfn[x]=low[x]=++tim; vis[x]=1; sta[++top]=x;
        for(int i=hd[x],u;i;i=nxt[i])
        {
            if(!dfn[u=to[i]])tarjan(u),low[x]=min(low[x],low[u]);
            else if(vis[u])low[x]=min(low[x],dfn[u]);
        }
        if(dfn[x]==low[x])
        {
            int y; cr++; mn[cr]=inf; mi[cr]=inf;
            while((y=sta[top])!=x)
                col[y]=cr,vis[y]=0,top--,mn[cr]=min(mn[cr],w[y]),mi[cr]=min(mi[cr],y);
            col[x]=cr; vis[x]=0; top--;
            mn[cr]=min(mn[cr],w[x]); mi[cr]=min(mi[cr],x);
        }
    }
    int find(int x)
    {
        int ret=mi[x];
        for(int i=hd2[x];i;i=nxt2[i])
        {
            if(mn[to2[i]]!=inf)break;//!
            ret=min(ret,find(to2[i]));
        }
        return ret;
    }
    int main()
    {
        n=rd(); p=rd();
        memset(w,0x3f,sizeof w);
        for(int i=1,id;i<=p;i++)id=rd(),w[id]=rd();
        m=rd();
        for(int i=1,x,y;i<=m;i++)
        {
            x=rd(); y=rd();
            add(x,y); 
        }
            //add(x=rd(),y=rd()),printf("add(%d,%d)
    ",x,y);
        for(int i=1;i<=n;i++)if(!dfn[i])tarjan(i);
        for(int i=1,u,v;i<=ct;i++)
            if((u=col[fr[i]])!=(v=col[to[i]]))add2(u,v),deg[v]++;
        bool fl=0; int id=inf;
        for(int i=1;i<=cr;i++)
        {
            if(deg[i])continue;
            if(mn[i]==inf)fl=1,id=min(id,find(i));
            else ans+=mn[i];
        }
        if(fl)printf("NO
    %d
    ",id);
        else printf("YES
    %d
    ",ans);
        return 0;
    }
  • 相关阅读:
    2013第38周日Java文件上传下载收集思考
    2013年第38周六这一刻,行动
    2013年9月20日突然的焦虑
    2013中秋
    2013第38周三
    2013年第38周二
    2013第38周一电话开会邮件
    for循环中一个不容小觑的问题
    NPOI 创建Excel,数据读取与写入
    linux下mysql数据的导出和导入
  • 原文地址:https://www.cnblogs.com/Zinn/p/9705793.html
Copyright © 2011-2022 走看看