FZU--1719 Spy Network--强连通+最小点基

Problem 1719 Spy Network

Accept: 96    Submit: 310
Time Limit: 1000 mSec    Memory Limit : 32768 KB

Problem Description

Due to the large number of infiltration of foreign espionage, national security is at a high level of crisis. If Spy A grasps Spy B’s evidence of crimes, Spy A can exposed Spy B. Some spies take bribes, and if we give a number of dollars to them, they are willing to hand over all their evidences they have. Therefore, if we are able to buy some spies, we would control the whole spy network.

That is because once we arrest a spy, we will get all evidences he has. Then we can arrest new spies to acquire new information.

Now we know those who are willing to take dollars, and the number of dollars they need. We know what evidences have been got for each spy as well. Suppose that there are n (n <= 3000) spies in total, who are labeled as a number between 1 and n.If we can control all spies, output minimal dollars required, otherwise output each spies we cannot control.

Input

The input consists of several test cases.For each case,the first line of input is an integer n. The second line is an integer p (1<=p<=n), which is the number of spies who accept dollars.Then following p lines, each of them contains two integers indicating the label of spies and the number he needs. An integer r (1 <= r <= 8000) followed, then r lines. Each contains two integers A and B, which means that Spy A has the evidence of Spy B.

Output

For each case, If we can control all spies, output “YES” in the first line and the minimal number of dollar we need in the second line. If we cannot, output “NO” in the first line and the label of spy that we cannot control and have the minimal number of label.

Sample Input

3 2 1 10 2 100 2 1 3 2 3 4 2 1 100 4 200 2 1 2 3 4

Sample Output

YES 110 NO 3

Source

FZU 2009 Summer Training Qualification -- Hero Revival 1

有些特殊人可以某种途径通知到,然后通知具有传递性,A->B B->C 那么A->C ,然后给出这些特殊人的标号和费用。

问能不能用最小的费用使得人全部被通知到,不能的话输出度为0的节点中编号最小的顶点编号。

分析:

先利用强连通缩点,成了一个新的图,求图中入度为0的节点,然后若特殊人不再此新点内,那么输出NO。

若所有缩点都符合,那么求出每一个缩点中的最小值。

答案累加。

 

#include<stdio.h>
#include<string.h>
#include<vector>
#include<algorithm>
using namespace std;
int head[100000];
int cmin[100000];
struct EdgeNode
{
    int to;
    int w;
    int next;
} e[1000000];
int n,cont,sig,cnt,tt;
vector<int >mp[3500];
int degree[3500];
int stack[3500];
int color[3500];
int vis[3500];
int low[3500];
int dfn[3500];
int need[3500];
void add(int from,int to)
{
    e[cont].to=to;
    e[cont].next=head[from];
    head[from]=cont++;
}
void Tarjan(int u)
{
    vis[u]=1;
    low[u]=dfn[u]=cnt++;
    stack[++tt]=u;
    for(int i=head[u]; i!=-1; i=e[i].next)
    {
        int v=e[i].to;
        if(vis[v]==0)
            Tarjan(v);
        if(vis[v]==1)
            low[u]=min(low[u],low[v]);
    }
    if(dfn[u]==low[u])
    {
        sig++;
        do
        {
            color[stack[tt]]=sig;
            //cmin[sig]=max(cmin[sig],need[stack[tt]]);
            vis[stack[tt]]=-1;
        }
        while(stack[tt--]!=u);
    }
}
void Slove()
{
    cnt=1;
    sig=0;
    tt=-1;
    memset(dfn,0,sizeof(dfn));
    memset(color,0,sizeof(color));
    memset(vis,0,sizeof(vis));
    memset(stack,0,sizeof(stack));
    memset(low,0,sizeof(low));
    memset(degree,0,sizeof(degree));
    for(int i=1; i<=n; i++)
        mp[i].clear();
    for(int i=1; i<=n; i++)
    {
        if(vis[i]==0)
            Tarjan(i);
    }
    //缩点染色之后的图中度为0的节点如果能够被贿赂就是Yes,否则就是No
    for(int i=1; i<=n; i++)
    {
        for(int j=head[i]; j!=-1; j=e[j].next)
        {
            int u=i,v=e[j].to;
            if(color[u]!=color[v])
            {
                mp[color[u]].push_back(color[v]);
                degree[color[v]]++;
            }
        }
    }
    memset(vis,0,sizeof(vis));
    //判断一下哪些点可以被贿赂。
    for(int i=1; i<=n; i++)
    {
        if(need[i]==-1)
            continue;
        vis[color[i]]=1;
    }
    int flag=0;
    for(int i=1; i<=sig; i++)
    {
        if(degree[i]==0&&vis[i]==0)
            flag=1;
    }
    if(flag==1)
    {
        printf("NO\n");
        for(int i=1; i<=n; i++)
        {
            if(degree[color[i]]==0&&vis[color[i]]==0)
            {
                printf("%d\n",i);
                break;
            }
        }
    }
    else
    {
        printf("YES\n");
        int output=0;
        for(int i=1; i<=sig; i++)
        {
            if(degree[i]==0)
            {
                int sum=0x3f3f3f3f;
                for(int j=1; j<=n; j++)
                {
                    if(color[j]==i)
                    {
                        if(need[j]!=-1)
                            sum=min(sum,need[j]);
                    }
                }
                output+=sum;
            }
        }
        printf("%d\n",output);
    }
}
int main()
{
    while(~scanf("%d",&n))
    {
        cont=0;
        memset(head,-1,sizeof(head));
        memset(need,-1,sizeof(need));
        int p;
        scanf("%d",&p);
        while(p--)
        {
            int num,val;
            scanf("%d%d",&num,&val);
            need[num]=val;
        }
        scanf("%d",&p);
        while(p--)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            add(x,y);
        }
        Slove();
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值