bzoj1093: [ZJOI2007]最大半连通子图 scc缩点+dag上dp

一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于图中任意
两点u,v,存在一条u到v的有向路径或者从v到u的有向路径。若G'=(V',E')满足V'?V,E'是E中所有跟V'有关的边,
则称G'是G的一个导出子图。若G'是G的导出子图,且G'半连通,则称G'为G的半连通子图。若G'是G所有半连通子图
中包含节点数最多的,则称G'是G的最大半连通子图。给定一个有向图G,请求出G的最大半连通子图拥有的节点数K
,以及不同的最大半连通子图的数目C。由于C可能比较大,仅要求输出C对X的余数。

解法:把scc缩点,同一个连通分量里肯定互相可达,然后变成了dag,只需要跑一个dag上dp找最长路即可,然后需要记录一下最长路方案数,需要注意的确定点之后边就确定了,所以scc缩点时需要判一下重边

/**************************************************************
    Problem: 1093
    User: walfy
    Language: C++
    Result: Accepted
    Time:4788 ms
    Memory:49420 kb
****************************************************************/
 
//#pragma comment(linker, "/stack:200000000")
//#pragma GCC optimize("Ofast,no-stack-protector")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
//#pragma GCC optimize("unroll-loops")
#include<bits/stdc++.h>
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define pi acos(-1.0)
#define ll long long
#define vi vector<int>
#define mod 1000000007
#define C 0.5772156649
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
#define pil pair<int,ll>
#define pli pair<ll,int>
#define pii pair<int,int>
#define cd complex<double>
#define ull unsigned long long
#define base 1000000000000000000
#define fio ios::sync_with_stdio(false);cin.tie(0)
 
using namespace std;
 
const double g=10.0,eps=1e-11;
const int N=100000+10,maxn=1000000+10,inf=0x3f3f3f3f,INF=0x3f3f3f3f3f3f3f3f;
 
int n,m,X;
stack<int>s;
vector<int>v[N],vv[N],ans[N];
int dfn[N],low[N];
int ins[N],inans[N];
int num,ind;
int a[maxn],b[maxn];
void tarjan(int u)
{
    ins[u]=2;
    low[u]=dfn[u]=++ind;
    s.push(u);
    for(int i=0;i<v[u].size();i++)
    {
        int t=v[u][i];
        if(dfn[t]==0)
        {
            tarjan(t);
            low[u]=min(low[u],low[t]);
        }
        else if(ins[t]==2)low[u]=min(low[u],dfn[t]);
    }
    if(low[u]==dfn[u])
    {
        ++num;
        while(!s.empty()){
            int k=s.top();
            s.pop();
            ins[k]=1;
            ans[num].push_back(k);
            inans[k]=num;
            if(k==u)break;
        }
    }
}
map<pii,int>ma;
void scc()
{
    for(int i=1;i<=n;i++)
        if(!dfn[i])
            tarjan(i);
    for(int i=0;i<m;i++)
    {
        int x=inans[a[i]],y=inans[b[i]];
        if(x!=y&&!ma[mp(x,y)])vv[x].pb(y),ma[mp(x,y)]=1;
    }
}
pii dp[N];
pii DP(int u)
{
    if(dp[u].fi!=-1)return dp[u];
    dp[u].fi=ans[u].size(),dp[u].se=1;
    for(int i=0;i<vv[u].size();i++)
    {
        int x=vv[u][i];pii te=DP(x);
        if(dp[u].fi<te.fi+ans[u].size())
        {
            dp[u]=te,dp[u].fi=te.fi+ans[u].size();
//            printf("%d %d %d %d\n",u,x,dp[u].fi,dp[u].se);
        }
        else if(dp[u].fi==te.fi+ans[u].size())
        {
            dp[u].se=(dp[u].se+te.se)%X;
//            printf("%d %d %d +++%d\n",u,x,dp[u].se,te.se);
        }
    }
    return dp[u];
}
int main()
{
    scanf("%d%d%d",&n,&m,&X);
    for(int i=0;i<m;i++)
    {
        scanf("%d%d",&a[i],&b[i]);
        v[a[i]].pb(b[i]);
    }
    scc();
    memset(dp,-1,sizeof dp);
    for(int i=1;i<=n;i++)
        DP(i);
    int ma=0;
    for(int i=1;i<=num;i++)ma=max(ma,dp[i].fi);//,printf("%d %d\n",dp[i].fi,dp[i].se);
    int ans=0;
    for(int i=1;i<=num;i++)if(dp[i].fi==ma)ans=(ans+dp[i].se)%X;
    printf("%d\n%d\n",ma,ans);
    return 0;
}
/***********************
 
***********************/
View Code

 

posted @ 2018-05-07 00:49  walfy  阅读(...)  评论(...编辑  收藏