BZOJ 1093 最大半连通子图(强连通分量+树形DP)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1093

题意:

思路:(1)首先,强连通分量中的一个点若在最大半连通子图中,则必定整个连通分量中的点都在,因为都在还是满足半连通的性质而且使得节点数更多。

(2)因此,求出强连通分量缩点,形成一个有向无环图,其实与树是差不多的。在这个图上DP一次即可,也就是找出最长链以及最长链的个数。

vector<int> g[N],g1[N];
int n,m,mod;

int dfn[N],low[N],visit[N],id;
int c[N],cNum,p[N];
int d[N];
stack<int> st;

void DFS(int u)
{
    if(u)
    {
        low[u]=dfn[u]=++id;
        st.push(u);
    }
    int i,v;
    FOR0(i,SZ(g[u]))
    {
        v=g[u][i];
        if(!dfn[v])
        {
            DFS(v);
            low[u]=min(low[u],low[v]);
        }
        else if(!visit[v]) low[u]=min(low[u],dfn[v]);
    }
    if(!u) return;
    if(low[u]==dfn[u])
    {
        cNum++;
        do
        {
            v=st.top();
            st.pop();
            p[cNum]++;
            c[v]=cNum;
            visit[v]=1;
        }while(u!=v);
    }
}

set<int> S;
int f[N],f1[N];

pair<int,int> dfs(int u)
{
    if(visit[u]) return MP(f[u],f1[u]);
    if(SZ(g1[u])==0) return MP(p[u],1);
    visit[u]=1;
    int i,v;
    pair<int,int> temp;
    FOR0(i,SZ(g1[u]))
    {
        v=g1[u][i];
        temp=dfs(v);
        if(temp.first+p[u]>f[u])
        {
            f[u]=temp.first+p[u];
            f1[u]=temp.second;
        }
        else if(temp.first+p[u]==f[u])
        {
            f1[u]=(f1[u]+temp.second)%mod;
        }
    }
    return MP(f[u],f1[u]);
}

void deal()
{
    int i,j,v,x;
    FOR1(i,n) FOR0(j,SZ(g[i]))
    {
        v=g[i][j];
        if(c[i]!=c[v])
        {
            x=c[i]*(cNum+1)+c[v];
            if(S.find(x)!=S.end()) continue;
            S.insert(x);
            d[c[v]]++;
            g1[c[i]].pb(c[v]);
        }
    }
    int Max=0,cnt=0;
    pair<int,int> p;
    clr(visit,0);
    FOR1(i,cNum) if(!d[i])
    {
        p=dfs(i);
        if(p.first>Max) Max=p.first,cnt=p.second;
        else if(p.first==Max) cnt=(cnt+p.second)%mod;
    }
    PR(Max); PR(cnt);
}

int main()
{
    RD(n,m,mod);
    int i,x,y;
    FOR1(i,m) RD(x,y),g[x].pb(y);
    FOR1(i,n) g[0].pb(i);
    DFS(0); deal();
}

BZOJ 1093 最大半连通子图(强连通分量+树形DP),布布扣,bubuko.com

时间: 2024-10-05 10:39:15

BZOJ 1093 最大半连通子图(强连通分量+树形DP)的相关文章

【BZOJ1093】【ZJOI2007】最大半连通子图 强连通分量缩点+sort去重边+拓扑排序

转载请注明出处:http://blog.csdn.net/vmurder/article/details/42610705 其实我就是觉得原创的访问量比未授权盗版多有点不爽233... 题解: 首先缩个点是必然,然后随便想想就知道缩点后需要最后是一条链, 也就是-- 缩点后求拓扑图最长路以及方案数. 呃,去重的部分我重标号排了个序水过. 代码: #include <cstdio> #include <cstring> #include <iostream> #inclu

BZOJ 1924 所驼门王的宝藏(强连通分量+树形DP)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1924 题意: 思路:首先建立所有可达点之间的有向图.之后求强连通分量SCC,缩点重新构图.然后就是一个树,树形DP一下即可. int n,r,c; map<i64,int> mp; map<int,int> mp1,mp2; struct node { int x,y,op; }; node a[N]; int visit[N]; vector<int> V1

HDU 3639 Hawk-and-Chicken (强连通分量+树形DP)

题目地址:HDU 3639 先用强连通分量缩点,缩点之后,再重新按缩点之后的块逆序构图,每个块的值是里边缩的点的个数,那么得到选票的最大的一定是重新构图后入度为0的块,然后求出来找最大值即可. 代码如下: #include <iostream> #include <string.h> #include <math.h> #include <queue> #include <algorithm> #include <stdlib.h>

BZOJ 1093 ZJOI 2007 最大半连通子图 强联通分量+拓扑图DP

题目大意:定义半连通图:图中任意两点之间可以单向到达.求一个图的最大半连通子图,和这个图最大半连通子图的个数. 思路:半连通图并不是一定要没有环..这题意让我理解的.. 其实想法什么的不难,想明白了也不难写.因为要保证半连通,所以要先处理出一个图的联通状况.先用Tarjan缩点得到DAG,在这个DAG上找到最长链的长度就是第一问的答案.第二问可以先找到所有f值等于答案的点,在这些点上反向记忆化搜索DP. 注意一个小地方,ans的初值是最大的scc的大小,如果是0的化会wa一个点. CODE: #

bzoj 1093 [ZJOI2007]最大半连通子图(scc+DP)

1093: [ZJOI2007]最大半连通子图 Time Limit: 30 Sec  Memory Limit: 162 MBSubmit: 2286  Solved: 897[Submit][Status][Discuss] Description Input 第一行包含两个整数N,M,X.N,M分别表示图G的点数与边数,X的意义如上文所述.接下来M行,每行两个正整数a, b,表示一条有向边(a, b).图中的每个点将编号为1,2,3…N,保证输入中同一个(a,b)不会出现两次. Outpu

【BZOJ 1093】 [ZJOI2007]最大半连通子图

1093: [ZJOI2007]最大半连通子图 Time Limit: 30 Sec  Memory Limit: 162 MB Submit: 1732  Solved: 679 [Submit][Status] Description Input 第一行包含两个整数N,M,X.N,M分别表示图G的点数与边数,X的意义如上文所述.接下来M行,每行两个正整数a, b,表示一条有向边(a, b).图中的每个点将编号为1,2,3-N,保证输入中同一个(a,b)不会出现两次. Output 应包含两行

最大半连通子图 bzoj 1093

最大半连通子图 (1.5s 128MB) semi [问题描述] 一个有向图G = (V,E)称为半连通的(Semi-Connected),如果满足:? u, v ∈V,满足u->v 或 v -> u,即对于图中任意两点u,v, 存在一条u到v的有向路径或者从v到u的有向路径. 若满足,则称G'是G的一个导出子图. 若G'是G的导出子图,且G'半连通,则称G'为G的半连通子图. 若G'是G所有半连通子图中包含节点数最多的,则称G'是G的最大半连通子图. 给定一个有向图G,请求出G的最大半连通子

BZOJ 1093: [ZJOI2007]最大半连通子图( tarjan + dp )

WA了好多次... 先tarjan缩点, 然后题意就是求DAG上的一条最长链. dp(u) = max{dp(v)} + totu, edge(u,v)存在. totu是scc(u)的结点数. 其实就是记忆化搜一下...重边就用set判一下 ------------------------------------------------------------------------------------------- #include<cstdio> #include<cstring

BZOJ 1093 ZJOI2007 最大半连通子图 Tarjan+动态规划

题目大意:定义半连通子图为一个诱导子图,其中任意两点(x,y)中x可到达y或y可到达x,求最大半连通子图的大小以及方案数 不就是个缩点之后拓扑序DP求最长链么 这题意逗不逗233333 注意缩点后连边不要连重复了 判重边那里我用了set... #include <set> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M