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; } /*********************** ***********************/