BZOJ 2208 JSOI 2010 连通数 Tarjan+bitset

题目大意:给出一张有向图,若一个点能够到达另一个点,那么说这两个点是一对联通点。问图中共有多少联通点。

思路:先进行一次Tarjan,求出所有的scc,对于一个scc中的点,对答案的贡献就是cnt^2,不同的scc组成了一张可拓扑图,然后对于每个scc维护一个bitset,来统计他自己和标号比它小的scc中共有多少个不同的点。然后进行dp,其中不停的或就可以了。

第一次使用bitset

CODE:

#include <bitset>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAXP 2010
#define MAX 4000010
using namespace std;

int points;
int head[MAXP],total;
int next[MAX],aim[MAX];

inline void Add(int x,int y)
{
    next[++total] = head[x];
    aim[total] = y;
    head[x] = total;
}

int dfn[MAXP],low[MAXP],_clock;
int stack[MAXP],top;
bool in_stack[MAXP];
int changed[MAXP],scc,num[MAXP];
bitset<MAXP> have[MAXP];

void Tarjan(int x)
{
    dfn[x] = low[x] = ++_clock;
    stack[++top] = x;
    in_stack[x] = true;
    for(int i = head[x]; i; i = next[i]) {
        if(!dfn[aim[i]])
            Tarjan(aim[i]),low[x] = min(low[x],low[aim[i]]);
        else if(in_stack[aim[i]])
            low[x] = min(low[x],dfn[aim[i]]);
    }
    if(dfn[x] == low[x]) {
        int temp;
        ++scc;
        do {
            temp = stack[top--];
            in_stack[temp] = false;
            changed[temp] = scc;
            ++num[scc];
        }while(temp != x);
    }
}

int main()
{
    cin >> points;
    for(int i = 1; i <= points; ++i)
        for(int x,j = 1; j <= points; ++j) {
            scanf("%1d",&x);
            if(x)   Add(i,j);
        }
    for(int i = 1; i <= points; ++i)
        if(!dfn[i]) Tarjan(i);
    for(int i = 1; i <= points; ++i)
        have[changed[i]][i] = true;
    int ans = 0;
    for(int i = 1; i <= scc; ++i) {
        ans += num[i] * num[i];
        bitset<MAXP> temp;
        for(int x = 1; x <= points; ++x)
            if(changed[x] == i)
                for(int j = head[x]; j; j = next[j])
                    if(changed[aim[j]] != i)
                        temp |= have[changed[aim[j]]];
        ans += num[i] * temp.count();
        have[i] |= temp;
    }
    cout << ans << endl;
    return 0;
}
时间: 2024-11-05 11:43:15

BZOJ 2208 JSOI 2010 连通数 Tarjan+bitset的相关文章

【BZOJ 2208】 [Jsoi2010]连通数

2208: [Jsoi2010]连通数 Time Limit: 20 Sec  Memory Limit: 512 MB Submit: 1431  Solved: 585 [Submit][Status][Discuss] Description Input 输入数据第一行是图顶点的数量,一个正整数N. 接下来N行,每行N个字符.第i行第j列的1表示顶点i到j有边,0则表示无边. Output 输出一行一个整数,表示该图的连通数. Sample Input 3 010 001 100 Samp

BZOJ 1823 JSOI 2010 盛宴 2-SAT

标题效果:有着n材料的种类,m陪审团. 每种材料具有两种不同的方法.每个法官都有两个标准.做出来的每一个法官的菜必须至少满足一个需求. 问:是否有这样一个程序. 思考:2-SAT经典的内置图形问题.因为每种材料只能有两种方法,约束条件通常就想到2-SAT.每个评委必须至少满足一种.这就是建图的条件. 所以连边A' -> B B' -> A 这样表示的是假设A不能满足某个评委,那么就必须让b满足这个评委. 然后就是Tarjan缩点,推断是否有个菜品的两种做法在一个scc中,若有就是无解,没有就是

BZOJ 1823 JSOI 2010 满汉全席 2-SAT

题目大意:有n种材料,m个评委.每种材料有两种不同的做法,每个评委有两个判定标准,做出来的菜品必须满足每一个评委至少一个要求.问有没有这样的方案. 思路:2-SAT经典建图问题.因为每一种材料只能有两种做法,这种约束条件通常就想到2-SAT.每一个评委必须至少满足一种,这就是建图的条件. 所以连边A' -> B B' -> A 这样表示的是如果A不能满足某个评委,那么就必须让b满足这个评委. 然后就是Tarjan缩点,判断是否有个菜品的两种做法在一个scc中,若有就是无解,没有就是有解. CD

BZOJ 1821 JSOI 2010 Group 部落划分 Group Kruskal

题目大意:给出平面上的一些点,现在要把这些点分成k组,求每组之间的距离的最小值的最大值. 思路:很水的题,只需要做一次最小生成树 ,然后去掉k-1条边,第k-2条边就是答案. CODE: #include <cmath> #include <cstdio> #include <iomanip> #include <cstring> #include <iostream> #include <algorithm> #define MAX

BZOJ 1822 JSOI 2010 Frozen Nova 冷冻波 二分+网络流

题目大意:在平面中有一些巫妖和一些小精灵,还有一些树会阻挡巫妖的视线.每一个巫妖都有一个攻击半径,如果一个小精灵在巫妖的攻击半径内,两点之间的连线没有树木阻挡,那么巫妖就可以秒杀小精灵.每个巫妖都有技能的CD.问最快多长时间可以使小精灵全灭. 思路:看出范围知算法系列.很明显的二分+最大流.二分最短时间,在这个时间内,每个巫妖可以发招time / CD + 1次.那么每次建图就从S到每个巫妖连能够输出的次数流量的边.每个巫妖向能攻击到的小精灵连边,之后每个小精灵向T连边.每次判断max_flow

[bzoj 1911][Apio 2010]特别行动队(斜率优化DP)

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1911 分析: 首先可以的到裸的方程f[i]=max{f[j]+a*(Si-Sj)^2+b*(Si-Sj)+c} 0<j<i 简化一下方程,我们知道对于一次项,最后结果肯定是b*Sn 所以可以写成f[i]=max{f[j]+a*(Si-Sj)^2+c} 0<j<i 我们不妨设0<x<y<i,且x比y优 即f[x]+a*(Si-Sx)^2+c>f[y]+a*

[Wikioi 2913][BZOJ 1029][JSOI 2007]建筑抢修

题目描述 Description 小刚在玩JSOI提供的一个称之为"建筑抢修"的电脑游戏: 经过了一场激烈的战斗,T部落消灭了所有z部落的入侵者.但是T部落的基地里已经有N个建筑设施受到了严重的损伤,如果不尽快修复的话,这些建筑设施将会完全毁坏.现在的情况是:T部落基地里只有一个修理工人,虽然他能瞬间到达任何一个建筑,但是修复每个建筑都需要一定的时间.同时,修理工人修理完一个建筑才能修理下一个建筑,不能同时修理多个建筑.如果某个建筑在一段时间之内没有完全修理完毕,这个建筑就报废了.你的

BZOJ 2208 JSOI2010 连通数 Tarjan+拓扑排序

题目大意:给定一个n个点的有向图,求有多少点对(x,y),使x沿边可到达y 设f[i][j]为从i到j是否可达 首先强联通分量中的任意两个点均可达 于是我们利用Tarjan缩点 缩点之后是一个拓扑图,我们求出拓扑序,沿着拓扑序从后向前DP,状态转移方程为: f[i][k]=or{ f[j][k] } (i有直连边到达j,1<=k<=n,n为强连通分量的个数) 鉴于每个点的值只会是1或者0,所以我们可以直接状压,或者干脆开bitset,整体取或即可 时间复杂度O(mn/32) 今天各种手滑...

(tarjan建图+topsort+状态压缩) bzoj 2208

2208: [Jsoi2010]连通数 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1489  Solved: 606[Submit][Status][Discuss] Description Input 输入数据第一行是图顶点的数量,一个正整数N. 接下来N行,每行N个字符.第i行第j列的1表示顶点i到j有边,0则表示无边. Output 输出一行一个整数,表示该图的连通数. Sample Input 3 010 001 100 Sample