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-;
const int N=+,maxn=+,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]=;
low[u]=dfn[u]=++ind;
s.push(u);
for(int i=;i<v[u].size();i++)
{
int t=v[u][i];
if(dfn[t]==)
{
tarjan(t);
low[u]=min(low[u],low[t]);
}
else if(ins[t]==)low[u]=min(low[u],dfn[t]);
}
if(low[u]==dfn[u])
{
++num;
while(!s.empty()){
int k=s.top();
s.pop();
ins[k]=;
ans[num].push_back(k);
inans[k]=num;
if(k==u)break;
}
}
}
map<pii,int>ma;
void scc()
{
for(int i=;i<=n;i++)
if(!dfn[i])
tarjan(i);
for(int i=;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)]=;
}
}
pii dp[N];
pii DP(int u)
{
if(dp[u].fi!=-)return dp[u];
dp[u].fi=ans[u].size(),dp[u].se=;
for(int i=;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=;i<m;i++)
{
scanf("%d%d",&a[i],&b[i]);
v[a[i]].pb(b[i]);
}
scc();
memset(dp,-,sizeof dp);
for(int i=;i<=n;i++)
DP(i);
int ma=;
for(int i=;i<=num;i++)ma=max(ma,dp[i].fi);//,printf("%d %d\n",dp[i].fi,dp[i].se);
int ans=;
for(int i=;i<=num;i++)if(dp[i].fi==ma)ans=(ans+dp[i].se)%X;
printf("%d\n%d\n",ma,ans);
return ;
}
/*********************** ***********************/
bzoj1093: [ZJOI2007]最大半连通子图 scc缩点+dag上dp的更多相关文章
- BZOJ1093 ZJOI2007最大半连通子图(缩点+dp)
发现所谓半连通子图就是缩点后的一条链之后就是个模板题了.注意缩点后的重边.写了1h+真是没什么救了. #include<iostream> #include<cstdio> # ...
- [luogu2272 ZJOI2007] 最大半连通子图 (tarjan缩点 拓扑排序 dp)
传送门 题目描述 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于图中任意两点u,v,存在一条u到v的有向路径或者从v到u的有向 ...
- [ZJOI2007]最大半连通子图 (Tarjan缩点,拓扑排序,DP)
题目链接 Solution 大概是个裸题. 可以考虑到,如果原图是一个有向无环图,那么其最大半联通子图就是最长的一条路. 于是直接 \(Tarjan\) 缩完点之后跑拓扑序 DP就好了. 同时由于是拓 ...
- 2018.11.06 bzoj1093: [ZJOI2007]最大半连通子图(缩点+拓扑排序)
传送门 先将原图缩点,缩掉之后的点权就是连通块大小. 然后用拓扑排序统计最长链数就行了. 自己yyyyyy了一下一个好一点的统计方法. 把所有缩了之后的点都连向一个虚点. 然后再跑拓扑,这样最后虚点的 ...
- [ZJOI2007]最大半连通子图(Tarjan,拓扑序DP)
[ZJOI2007]最大半连通子图 题目描述 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于图中任意两点u,v,存在一条u到v ...
- BZOJ1093 [ZJOI2007]最大半连通子图 【tarjan缩点 + DAG最长路计数】
题目 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于图中任意 两点u,v,存在一条u到v的有向路径或者从v到u的有向路径.若G ...
- BZOJ1093 [ZJOI2007]最大半连通子图
Description 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于图中任意两点u,v,存在一条u到v的有向路径或者从v到u ...
- bzoj1093[ZJOI2007]最大半连通子图(tarjan+拓扑排序+dp)
Description 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于图中任意两点u,v,存在一条u到v的有向路径或者从v到u ...
- 【tarjan 拓扑排序 dp】bzoj1093: [ZJOI2007]最大半连通子图
思维难度不大,关键考代码实现能力.一些细节还是很妙的. Description 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于 ...
随机推荐
- linux mysql备份
许多备份方案: http://blog.jobbole.com/14012/ 采用的: mysqldump ---user admin ---password=password mydatabase ...
- boost circular buffer环形缓冲类
Boost.Circular_buffer维护了一块连续内存块作为缓存区,当缓存区内的数据存满时,继续存入数据就覆盖掉旧的数据. 它是一个与STL兼容的容器,类似于 std::list或std::de ...
- Zen-cart产品页面随机调用Wordpress文章
<?php require('./wordpress所在目录/wp-blog-header.php'); ?><?php$rand_posts = get_posts('number ...
- 微信小程序组件slider
表单组件slider:官方文档 Demo Code: var pageData = {} for (var i = 1; i < 5; i++) { (function (index) { pa ...
- C# 使用 SqlBulkCopy 类批量复制数据到数据库
最近公司需要优化导入的问题,由于之前使用的方式是生成 Insert 语句插入数据库,数据量小的时候还行,但是随着发展数据量渐渐大了,之前的方法性能就跟不上了,于是发现了 SqlBulkCopy 这个类 ...
- php注册审查
思路 用户注册后就有该条用户记录,你对用户表设一个“审核状态”字段,默认值设为“未审核”,然后你写几句审核代码做成一个功能,按照你们的意愿若审核通过你把审核状态改为“已审核”就行了.用户想进行各种操作 ...
- PKU 2155 Matrix(裸二维树状数组)
题目大意:原题链接 题意很简单,就不赘诉了. 解题思路: 使用二维树状数组,很裸的题. 二维的写起来也很方便,两重循环. Add(int x,int y,int val)表示(x,y)-(n,n)矩形 ...
- cocos2dx lua invalid 'cobj' in function 'lua_cocos2dx‘ 躺坑
for 循环中保存了创建的 Node节点到 userdata 数据结构中 再次引用发现 一直报 LUA ERROR: [string ".\framework/cocos2dx/NodeEx ...
- spark[源码]-Pool分析
概述 这篇文章主要是分析一下Pool这个任务调度的队列.整体代码量也不是很大,正好可以详细的分析一下,前面在TaskSchedulerImpl提到大体的功能,这个点在丰富一下吧. DAGSchedul ...
- Linux中find
Linux中find常见用法示例 ·find path -option [ -print ] [ -exec -ok command ] {} \; find命令的参数 ...