Graph_Master(连通分量_H_Trajan+拓扑序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的余数。
题解:拿到题目是懵的,这个题目要我做什么玩意??后来去翻了翻演算法,导出子图的意思就是拿出一些点,并且保留这些点之间所有的边,然后我就明白了,这题就是要Tarjan缩完点之后,找出拥有最多点的路径,并且求出有几条这样的路径。好了,Tarjan已经打到很熟练了,而且还是这种缩点的Tarjan。问题就转化成了如何找出拥有最多节点的路径,以及这种路径的数量。百度之后发现有个东西叫拓扑序dp??我是谁?我怎么从来没有听说过?行吧,那就学吧,发现就是一个很简单的dp,一边做拓扑序的时候一边把dp做了,说是dp,其实更像是一个递推,过程挺好理解的,写起来难度也不大。
坑点:我个人觉得这题的数据有点奇怪,因为我自己打的代码是没有if used[v] == cur then continue 以及 used[v] = cur。因为我想到,既然缩点了,而且rebuild过程也是符合我的直观判断,及不会出现重边,但是这样交上去WA了,于是乎我百度到了别人的AC代码,就差了这个部分,可以说是很难受了,题目是下午A的,但是到现在也没有思路为啥要多个used,希望如果哪位看官看出了问题所在,能够告知一下我。
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#define clr(a,b) memset(a,b,sizeof(a))
using namespace std;
const int M = 1e6 + 16;
const int N = 1e5 + 16;
struct Edge
{
int u, v, nxt;
};
Edge edge[M];
int low[N], dfn[N], sta[N], col[N];
bool vis[N];
int dep, top, sum;
vector<int> son[N];
int n, m, X;
int head[N], ecnt;
void _add( int u, int v )
{
edge[ecnt].u = u;
edge[ecnt].v = v;
edge[ecnt].nxt = head[u];
head[u] = ecnt ++;
}
void tarjan( int u )
{
low[u] = dfn[u] = ++dep;
sta[++top] = u;
vis[u] = 1;
for ( int i = head[u]; i+1; i = edge[i].nxt )
{
int v = edge[i].v;
if ( !dfn[v] )
{
tarjan(v);
low[u] = min( low[u], low[v] );
}
else if ( vis[v] )
low[u] = min( low[u], low[v] );
}
if ( dfn[u] == low[u] )
{
col[u] = ++sum;
vis[u] = 0;
while ( sta[top] != u )
{
col[sta[top]] = sum;
vis[sta[top--]] = 0;
}
top --;
}
}
int in[N];
void rebuild()
{
for ( int i = 1; i <= n; i ++ )
{
for ( int j = head[i]; j+1; j = edge[j].nxt )
{
int v = edge[j].v;
if ( col[v] != col[i] )
{
son[col[i]].push_back(col[v]);
in[col[v]] ++;
}
}
}
}
void init()
{
ecnt = top = sum = dep = 0;
clr(head,-1);
clr(dfn,0);
clr(sta,0);
clr(col,0);
clr(vis,0);
for ( int i = 0; i <= n; i ++ )
son[i].clear();
}
int f[N], g[N];
int val[N];
int used[N];
void tp()
{
queue<int> q;
for ( int i = 1; i <= sum; i ++ )
{
if ( in[i] == 0 )
q.push(i);
f[i] = val[i], g[i] = 1;
}
while ( !q.empty() )
{
int cur = q.front(); q.pop();
for ( int i = 0; i < son[cur].size(); i ++ )
{
int v = son[cur][i];
in[v] --;
if ( in[v] == 0 )
q.push(v);
if ( used[v] == cur ) continue;
if ( f[cur] + val[v] > f[v] )
{
f[v] = f[cur] + val[v];
g[v] = g[cur];
}
else if ( f[cur] + val[v] == f[v] )
g[v] = ( g[v] + g[cur] ) % X;
used[v] = cur;
}
}
}
int main()
{
init();
scanf("%d%d%d", &n, &m, &X );
for ( int i = 0; i < m; i ++ )
{
int u, v;
scanf("%d%d", &u, &v);
_add(u,v);
}
for ( int i = 1; i <= n; i ++ )
if ( !dfn[i] )
tarjan(i);
rebuild();
for ( int i = 1; i <= n; i ++ )
val[col[i]] ++;
tp();
int ans1, ans2;
ans1 = ans2 = 0;
for ( int i = 1; i <= sum; i ++ )
{
if ( f[i] > ans1 )
ans1 = f[i], ans2 = g[i];
else if ( f[i] == ans1 )
ans2 = ( ans2 + g[i] ) % X;
}
printf("%d\n%d\n", ans1, ans2);
return 0;
}
Graph_Master(连通分量_H_Trajan+拓扑序dp)的更多相关文章
- [十二省联考2019]字符串问题——后缀自动机+parent树优化建图+拓扑序DP+倍增
题目链接: [十二省联考2019]字符串问题 首先考虑最暴力的做法就是对于每个$B$串存一下它是哪些$A$串的前缀,然后按每组支配关系连边,做一遍拓扑序DP即可. 但即使忽略判断前缀的时间,光是连边的 ...
- [NOIP2017]逛公园 最短路图 拓扑序DP
---题面--- 题解: 挺好的一道题. 首先我们将所有边反向,跑出n到每个点的最短路,然后f[i][j]表示从i号节点出发,路径长比最短路大j的方案数. 观察到,如果图中出现了0环,那么我们可以通过 ...
- [bzoj3887][Usaco2015 Jan]Grass Cownoisseur_trajan_拓扑排序_拓扑序dp
[Usaco2015 Jan]Grass Cownoisseur 题目大意:给一个有向图,然后选一条路径起点终点都为1的路径出来,有一次机会可以沿某条边逆方向走,问最多有多少个点可以被经过?(一个点在 ...
- [ZJOI2007]最大半连通子图(Tarjan,拓扑序DP)
[ZJOI2007]最大半连通子图 题目描述 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于图中任意两点u,v,存在一条u到v ...
- 拓扑序+dp Codeforces Round #374 (Div. 2) C
http://codeforces.com/contest/721/problem/C 题目大意:给你有向路,每条路都有一个权值t,你从1走到n,最多花费不能超过T,问在T时间内最多能访问多少城市? ...
- bzoj5017 炸弹 (线段树优化建图+tarjan+拓扑序dp)
直接建图边数太多,用线段树优化一下 然后缩点,记下来每个点里有多少个炸弹 然后按拓扑序反向dp一下就行了 #include<bits/stdc++.h> #define pa pair&l ...
- NOIP2017 逛公园 题解报告 【最短路 + 拓扑序 + dp】
题目描述 策策同学特别喜欢逛公园.公园可以看成一张NNN个点MMM条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,NNN号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花 ...
- 【BZOJ-4562】食物链 记忆化搜索(拓扑序 + DP)
4562: [Haoi2016]食物链 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 133 Solved: 112[Submit][Status] ...
- [正经分析] DAG上dp两种做法的区别——拓扑序与SPFA
在下最近刷了几道DAG图上dp的题目. 要提到的第一道是NOIP原题<最优贸易>.这是一个缩点后带点权的DAG上dp,它同时规定了起点和终点. 第二道是洛谷上的NOI导刊题目<最长路 ...
随机推荐
- iOS 内存管理(转载)
N久没维护这个博客了,从开始接触编程到现在已经三四年了.不太习惯写博客,这应该是个不好的习惯.所以从哪哪天开始,我得改变自己 (: . 文采不太好,因此很多的文章都会借鉴他人的,但是我一 ...
- intelij IDEA在启动tomcat时控制台日志乱码
1.在idea安装目录的bin下修改idea.exe.vmoptions和idea64.exe.vmoptions,添加 -Dfile.encoding=UTF-8 -Dconsole.encodin ...
- 剑指Offer——整数中1出现的次数(从1到n整数中1出现的次数)
题目描述: 求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1.10.11.12.13因此共出现6次,但是对于后面问题他就没辙了 ...
- react 日期
1.首先安装moment : npm install moment --save 2.在文件中引用: import moment from 'moment' 3.使用方式: 当前时间:moment() ...
- (转)Unity3d的3种截图方法
下面是我总结的.在u3d中的,三种截屏方法: 1.使用Application类下的CaptureScreenshot方法. void CaptureScreen() { Application.Cap ...
- Django在生产环境中的部署
基本思路 1.方案:Nginx+uwsgi 这样大体的流程是:nginx作为服务器最前端,负责接收client的所有请求,统一管理.静态请求由Nginx自己处理.非静态请求通过uwsgi传递给Djan ...
- 对比python的进程和线程:多线程是假的
进程,是系统进行资源分配最小单位(拥有独立的内存单元).(python中多进程是真的) 线程,是操作系统最小的执行单位(共享内存资源),比进程还小.(python中多线程是假的,因为cpython解释 ...
- Installshield 宏定义控制版本
定义宏 在Build =>Setting => 以空格为准定义宏 使用宏 在方法里 #if 宏名称 代码 #else 代码 #endif
- 详解Spark sql用户自定义函数:UDF与UDAF
UDAF = USER DEFINED AGGREGATION FUNCTION Spark sql提供了丰富的内置函数供猿友们使用,辣为何还要用户自定义函数呢?实际的业务场景可能很复杂,内置函数ho ...
- sdut3140 A*B(math)
题目:传送门 题目描述 Your task is to find the minimal positive integer number Q so that the product of digits ...