CF427C 强连通

Description

Your city has n junctions. There are mone-way roads between the junctions. As a mayor of the city, you have to ensure the security of all the junctions.

To ensure the security, you have to build some police checkposts. Checkposts can only be built in a junction. A checkpost at junction ican protect junction j if either i = j or the police patrol car can go to j from i and then come back to i.

Building checkposts costs some money. As some areas of the city are more expensive than others, building checkpost at some junctions might cost more money than other junctions.

You have to determine the minimum possible money needed to ensure the security of all the junctions. Also you have to find the number of ways to ensure the security in minimum price and in addition in minimum number of checkposts. Two ways are different if any of the junctions contains a checkpost in one of them and do not contain in the other.

Input

In the first line, you will be given an integer n, number of junctions (1 ≤ n ≤ 105). In the next line, n space-separated integers will be given. The ith integer is the cost of building checkpost at the ith junction (costs will be non-negative and will not exceed 109).

The next line will contain an integer m (0 ≤ m ≤ 3·105). And each of the next m lines contains two integers ui and vi (1 ≤ ui, vi ≤ nu ≠ v). A pair ui, vi means, that there is a one-way road which goes from ui to vi. There will not be more than one road between two nodes in the same direction.

Output

Print two integers separated by spaces. The first one is the minimum possible money needed to ensure the security of all the junctions. And the second one is the number of ways you can ensure the security modulo 1000000007(109 + 7).

Sample Input

Input

3 1 2 3 3 1 2 2 3 3 2

Output

3 1

题意:在每个强连通图中建一个派出所,使总费用最低,并且总费用最低的建法有多少种。思路:其实就是强连通,之后每个连通图在找最小费用点,并记录个数,最后把每个连通图的最小费用相加,记得会爆int,      把每个连通图的最小费用点个数相乘即可;   我发现自己还是太弱了,我把每个强连通找出来并标记,在查找,后来看看别人的代码,      其实在Tarjan函数里出栈的时候就可以找到了。真是666666.   自己AC代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
typedef __int64 LL;
const int maxn = 100009;
const int maxm = 400009;
const LL inf = (LL)1<<50;
const int MOD = 1000000000 + 7;
struct node
{
    int v,next;
}eg[maxm];
int head[maxn],vis[maxn],sta[maxn],insta[maxn],dfn[maxn],low[maxn],belong[maxn];
int count[maxn],val[maxn];
int tot,color,top,n,m,Index;

vector<int>vec[maxn];

void add(int a,int b)
{
    eg[tot].v = b;
    eg[tot].next = head[a];
    head[a] = tot++;
}

void init()
{
    tot = top = color =  Index = 0;
    memset(head,-1,sizeof(head));
    memset(insta,0,sizeof(insta));
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(belong,0,sizeof(belong));
    memset(vis,0,sizeof(vis));
//memset(count,0,sizeof(count));
    for(int i=1;i<maxn;i++)vec[i].clear();
}
inline int min(int a,int b){return a < b ? a : b;}

void input()
{
    int i,a,b;
    for(i=1;i<=n;i++)
        scanf("%d",&val[i]);
    scanf("%d",&m);
    for(i=0;i<m;i++)
    {
        scanf("%d%d",&a,&b);
        add(a,b);
    }
}

void Tarjan(int u)
{
    dfn[u] = low[u] = ++Index;
    sta[top++] = u;
    insta[u] = 1;
    for(int i = head[u];i+1;i=eg[i].next)
    {
        int v = eg[i].v;
        if(!dfn[v])
        {
            Tarjan(v);
            low[u] = min(low[u],low[v]);
        }else if(insta[v])
            low[u] = min(low[u],dfn[v]);
    }
    if(dfn[u] == low[u])
    {
        int v ;
        color++;
        do
        {
            v = sta[--top];
            insta[v] = 0;
            belong[v] = color;
        }while(v!=u);
    }
}

void work()
{
    int i,j;
    for(i=1;i<=n;i++)
    {
        if(!dfn[i]) Tarjan(i);
    }
//    printf("color ==%d\n",color);
    for(int u=1;u<=n;u++)
    {
        for(i=head[u];i+1;i =eg[i].next)
        {
            int v = eg[i].v;
                int k = belong[u];
                if(!vis[u])
                    vec[k].push_back(u),vis[u] = 1;
                 k = belong[v];
                if(!vis[v])
                    vec[k].push_back(v),vis[v] = 1;
        }
    }
    for(i=1;i<=n;i++)
    {
        if(!vis[i])
        {
            int k = belong[i];
            vec[k].push_back(i);
            vis[i] = 1;
        }
    }
    LL cost = 0;
    LL sum = 1;
    for(i=1; i <= color; i++)
    {
        int minnum = 0x7fffffff;
        int count = 0;
        for(j =0;j<vec[i].size();j++)
        {

            int v = vec[i][j];
    //    printf(" %d",v);
            minnum = min(minnum,val[v]);
        }
        for(j=0;j<vec[i].size();j++)
        {
            int v = vec[i][j];
            if(val[v] == minnum) count++;
        }
        cost +=minnum;
        sum = sum * count;
        sum %= MOD;
//        puts("");
    }
    printf("%I64d %I64d\n",cost,sum);
}
int main()
{
//    int i,a,b,w;
    while(~scanf("%d",&n))
    {
        init();
        input();
    //    for(int i=1;i<=n;i++)printf("%d  ",val[i]);
        work();
    }
    return 0;
}

最后改进代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
typedef __int64 LL;
const int maxn = 100009;
const int maxm = 400009;
const LL inf = (LL)1<<50;
const LL MOD = 1000000000 + 7;
struct node
{
    int v,next;
}eg[maxm];
int head[maxn],sta[maxn],insta[maxn],dfn[maxn],low[maxn];
int val[maxn];
int tot,color,top,n,m,Index;
LL cost,produce;

vector<int>vec[maxn];

void add(int a,int b)
{
    eg[tot].v = b;
    eg[tot].next = head[a];
    head[a] = tot++;
}

void init()
{
    tot = top = color =  Index = 0;
    memset(head,-1,sizeof(head));
    memset(insta,0,sizeof(insta));
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
//    memset(belong,0,sizeof(belong));
//    memset(vis,0,sizeof(vis));
//memset(count,0,sizeof(count));
    for(int i=1;i<maxn;i++)vec[i].clear();
}
inline int min(int a,int b){return a < b ? a : b;}

void input()
{
    int i,a,b;
    for(i=1;i<=n;i++)
        scanf("%d",&val[i]);
    scanf("%d",&m);
    for(i=0;i<m;i++)
    {
        scanf("%d%d",&a,&b);
        add(a,b);
    }
}

void Tarjan(int u)
{
    dfn[u] = low[u] = ++Index;
    sta[top++] = u;
    insta[u] = 1;
    for(int i = head[u];i+1;i=eg[i].next)
    {
        int v = eg[i].v;
        if(!dfn[v])
        {
            Tarjan(v);
            low[u] = min(low[u],low[v]);
        }else if(insta[v])
            low[u] = min(low[u],dfn[v]);
    }
    if(dfn[u] == low[u])
    {
        int v ;
    //    color++;
        int minnum = MOD;
        int sum = 0;
        do
        {
            v = sta[--top];
            insta[v] = 0;
    //        belong[v] = color;
            if(minnum == val[v]) sum ++;
            else if(minnum > val[v]) sum = 1,minnum = val[v];
        }while(v!=u);
        cost +=minnum;
        produce = (produce*sum) % MOD;

    }
}

void work()
{
    int i;
    cost = 0;
    produce = 1;
    for(i=1;i<=n;i++)
    {
        if(!dfn[i]) Tarjan(i);
    }
    printf("%I64d %I64d\n",cost,produce);

}
int main()
{

    while(~scanf("%d",&n))
    {
        init();
        input();
    //    for(int i=1;i<=n;i++)printf("%d  ",val[i]);
        work();
    }
    return 0;
}

/*

  10
1 3 2 2 1 3 1 4 10 10
12
1 2
2 3
3 1
3 4
4 5
5 6
5 7
6 4
7 3
8 9
9 10
10 9

10
1 1 1 1 1 1 1 2 2 2
15
2 3
2 4
4 1
4 7
4 10
4 5
4 8
2 6
3 2
1 2
7 2
10 2
5 2
8 2
6 2

  */

CF427C 强连通

时间: 2024-11-08 22:02:33

CF427C 强连通的相关文章

Kosaraju算法解析: 求解图的强连通分量

1. 定义 连通分量:在无向图中,即为连通子图. 上图中,总共有四个连通分量.顶点A.B.C.D构成了一个连通分量,顶点E构成了一个连通分量,顶点F,G和H,I分别构成了两个连通分量. 强连通分量:有向图中,尽可能多的若干顶点组成的子图中,这些顶点都是相互可到达的,则这些顶点成为一个强连通分量. 上图中有三个强连通分量,分别是a.b.e以及f.g和c.d.h. 2. 连通分量的求解方法 对于一个无向图的连通分量,从连通分量的任意一个顶点开始,进行一次DFS,一定能遍历这个连通分量的所有顶点.所以

POJ 2186 Popular Cows 强连通分量模板

题意 强连通分量,找独立的块 强连通分量裸题 #include <cstdio> #include <cstdlib> #include <cstring> #include <string> #include <algorithm> #include <iostream> using namespace std; const int maxn = 50005; int n, m; struct Edge { int v, next;

USACO network of school 强连通分量

这个题的意思是有一个有向图, 每个顶点可以发送软件到与其相连的顶点上, 现在问1,至少发送给几个顶点能满足所有顶点都收到软件, 2:如果想让这个图变成强连通图,至少添几条边.  特例是给定的图是一个强连通图的话答案是1, 0. 一般情况下我们先将这个图的强连通分量求出来缩成一个点然后统计入度为0的点和出度为0的点的个数, 答案一就是入度为0的点的个数, 答案就是他们两个之间的最大值.代码如下: /* ID: m1500293 LANG: C++ PROG: schlnet */ #include

hdu3861 强连通+最小路径覆盖

题意:有 n 个点,m 条边的有向图,需要将这些点分成多个块,要求:如果两点之间有路径能够互相到达,那么这两个点必须分在同一块:在同一块内的任意两点相互之间至少要有一条路径到达,即 u 到达 v 或 v 到达 u:每个点都只能存在于单独一个块内.问最少需要划分多少块. 首先,对于如果两点之间能够相互到达则必须在同一块,其实也就是在同一个强连通分量中的点必须在同一块中,所以首先就是强连通缩点.然后在同一块内的任意两点之间要有一条路,那么其实就是对于一块内的强连通分量,至少要有一条路径贯穿所有分量.

HDU 3072 Intelligence System (强连通分量)

题目地址:HDU 3072 这题一开始理解错题目意思了..(不得不吐槽一下题目意思确实不好理解..)用的强连通+最小生成树做的...然后错了好多遍...sad..题目意思是从一个给定点向其他所有点通信的最少花费,那么入度为0的点肯定是那个给定点.然后对于其它点,枚举就好了.找一个到他花费最少的点的花费. 代码如下: #include <iostream> #include <string.h> #include <math.h> #include <queue&g

强连通分量(学习心得)

定义:有向图强连通分量:在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通如果有向图G的每两个顶点都强连通,称G是一个强连通图.有向图的极大强连通子图,称为强连通分量. 求强连通分量: vector<int>pic[maxn]; int dfn[maxn],low[maxn],ans[maxn]; bool ins[maxn]; stack<int>st; int dind=0,block=

UVA-11324 The Largest Clique 【有向图强连通+缩点+DP】

题目链接:https://vjudge.net/problem/UVA-11324 题目大意:给定一张有向图G,求一个结点数最大的结点集,集合中每两个点都至少有一条路径相连(方向任意). 题解: 易知如果一个点被选择,则它所在强连通分量中的其他点也一定要选,如果不选,则其他点也不可选,因此先求出强连通分量,利用缩点创建出另一张有向图G2,每个结点的权值就是该强连通分量的结点数,再DP求解. 代码: 1 #include<bits/stdc++.h> 2 using namespace std;

POJ 2186:Popular Cows(强连通分量)

[题目链接] http://poj.org/problem?id=2186 [题目大意] 给出一张有向图,问能被所有点到达的点的数量 [题解] 我们发现能成为答案的,只有拓扑序最后的SCC中的所有点, 那么我们从其中一个点开始沿反图dfs,如果能访问到全图, 则答案为其所在SCC的大小,否则为0. [代码] #include <cstdio> #include <algorithm> #include <vector> #include <cstring>

【学习整理】Tarjan:强连通分量+割点+割边

Tarjan求强连通分量 在一个有向图中,如果某两点间都有互相到达的路径,那么称中两个点强联通,如果任意两点都强联通,那么称这个图为强联通图:一个有向图的极大强联通子图称为强联通分量.   算法可以在 的时间内求出一个图的所有强联通分量. 表示进入结点 的时间 表示从 所能追溯到的栈中点的最早时间 如果某个点 已经在栈中则更新  否则对 进行回溯,并在回溯后更新  #include<iostream> #include<cstdlib> #include<cstdio>