P1262 间谍网络+Trajan 缩点(有向图)

题目链接

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int num=3010;
const int inf=0x3f3f3f3f;
/*------------------*/
struct node{
    int u,v,next;
}e[num*3];
int head[num],cnt,cnt2;
int ip[num];
/*------------------*/
int dfn[num],low[num],ind,stack[num],t,cnt3,f[num],w[num],w2[num];
bool vis[num];
int person[num];
/*------------------*/
struct point{
    int id,v,fa;//id编号,v,费用,fa,父节点;
}a[num];
/*------------------*/
/*------------------*/
int n,p,r,all;
void int_i(void)
{
    all=0;
    memset(w,inf,sizeof(w));
    cnt=-1;
    memset(head,-1,sizeof(head));
    ind=0;
    memset(vis,0,sizeof(vis));
    memset(dfn,0,sizeof(dfn));
    memset(low,-1,sizeof(low));
    t=0;
    memset(stack,0,sizeof(stack));
    cnt3=0;
    memset(w,inf,sizeof(w));
    memset(w2,inf,sizeof(w2));
    memset(person,inf,sizeof(person));
    memset(ip,0,sizeof(ip));
    all=0;
    return ;
}
void addedge(int u,int v)
{
    e[++cnt].u=u;
    e[cnt].v=v;
    e[cnt].next=head[u];
    head[u]=cnt;//忘了写这句,居然过了六组样例&..&;改了两个多小时的bug!!!!
    return ;
}
void addedge2(int u,int v)
{
    e[++cnt].u=u;
    e[cnt].v=v;
    e[cnt].next=head[u];
    e[cnt].flag=false;
    ip[v]++;
    head[u]=cnt;
    return;
}
void tarjan(int u)
{
    int v;
    dfn[u]=low[u]=++ind;
    stack[++t]=u;
    vis[u]=true;
    for(int i=head[u];i!=-1;i=e[i].next)
    {
        v=e[i].v;
        if(!dfn[v])
        {
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(vis[v])
        {
            low[u]=min(low[u],dfn[v]);
        }
    }
    if(dfn[u]==low[u])
    {
        ++cnt3;
        do{
            v=stack[t--];
            vis[v]=false;
            f[v]=cnt3;
            w2[cnt3]=min(w2[cnt3],w[v]);
            person[cnt3]=min(person[cnt3],v);
            // printf("cnt3==%d,v==%d\n",cnt3,v);
        }while(v!=u);
    }
    return ;
}

int main()
{
    int x=0,y;
    bool flag;
    //while(scanf("%d",&n)!=EOF)
    //{
    int_i();
    scanf("%d%d",&n,&p);
    for(int i=1;i<=p;i++)
    {
        scanf("%d%d",&x,&y);
        w[x]=y;
    }
    scanf("%d",&r);
    for(int i=1;i<=r;i++)
    {
        scanf("%d%d",&x,&y);
        addedge(x,y);
    }
    for(int i=1;i<=n;i++)
    {
        if(!dfn[i]){
            tarjan(i);
        }
    }
    cnt2=cnt;
    memset(head,-1,sizeof(head));//二次使用head数组
    cnt=-1;
    for(int i=0;i<=cnt2;i++)
    {
        x=e[i].u;
        y=e[i].v;
        if(f[x]!=f[y])
        {
            // printf("fx==%d,fy==%d\n",f[x],f[y]);
            addedge2(f[x],f[y]);
        }
    }
    // for(int i=1;i<=cnt3;i++)
    // printf("ip=%d\n",ip[i]);
    flag=true;
    for(int i=1;i<=cnt3;i++)
    {
        if(ip[i]==0)
        {
            //  printf("ip==%d,w==%d,per==%d\n",i,w[i],person[i]);
            if(w2[i]==inf){
                x=i;
                flag=false;
                break;
            }
            else
            {
                all+=w2[i];
            }
        }
    }

    if(!flag){
        printf("NO\n%d\n",person[x]);
    }
    else {
        printf("YES\n%d\n",all);
    }
    //}
    return 0;
}

/*
 4
 2
 1 100
 4 200
 2
 1 2
 3 4

 4
 2
 1 100
 4 200
 2
 1 2
 3 4

 3
 2
 1 10
 2 100
 2
 1 3
 2 3

 3
 2
 1 10
 2 100
 2
 1 3
 2 3
 */

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值