Description

  一个有向图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的余数。

Input

  第一行包含两个整数N,M,X。N,M分别表示图G的点数与边数,X的意义如上文所述接下来M行,每行两个正整
数a, b,表示一条有向边(a, b)。图中的每个点将编号为1,2,3…N,保证输入中同一个(a,b)不会出现两次。N ≤1
00000, M ≤1000000;对于100%的数据, X ≤10^8

Output

  应包含两行,第一行包含一个整数K。第二行包含整数C Mod X.

Sample Input

6 6 20070603
1 2
2 1
1 3
2 4
5 6
6 4

Sample Output

3
3
 
正解:tarjan+DP
解题报告:
  遥遥今天讲课讲了这道题,然后感觉这是最水的,就高兴地开了坑,调了半个晚上都没有发现为什么wa了。
  最后发现居然是有重边!!!!!!然后方案重复计算了,但我当时没有马上想出怎么判重,于是看了网上的题解发现可以用set,我真傻真的。
  做法其实挺简单,首先tarjan缩环,然后重构图,可以想到我们一定是在重构的图上选取一条链,使得链的点权和最大。DP可做。
 
 
 //It is made by jump~
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <ctime>
#include <vector>
#include <queue>
#include <map>
#include <set>
#ifdef WIN32
#define OT "%I64d"
#else
#define OT "%lld"
#endif
using namespace std;
typedef long long LL;
const int MAXN = ;
const int MAXM = ;
int MOD;
int n,m,ecnt,ans,num;
int first[MAXN],to[MAXM],next[MAXM];
bool pd[MAXN];
int dfn[MAXN],low[MAXN];
int Stack[MAXN*],top,belong[MAXN];
int size[MAXN],cnt;
int head[MAXN],ru[MAXN],f[MAXN];
bool vis[MAXN]; set<pair<int,int> >bst;//要有一个空格 struct edge{
int v,next;
}e[MAXM]; inline int getint()
{
int w=,q=;
char c=getchar();
while((c<'' || c>'') && c!='-') c=getchar();
if (c=='-') q=, c=getchar();
while (c>='' && c<='') w=w*+c-'', c=getchar();
return q ? -w : w;
} inline void dfs(int x){
dfn[x]=++ecnt; low[x]=dfn[x];
pd[x]=; Stack[++top]=x;
for(int i=first[x];i;i=next[i]) {
int v=to[i];
if(!dfn[v]) { dfs(v); if(low[v]<low[x]) low[x]=low[v]; }
else if(pd[v]) low[x]=min(low[v],low[x]);
}
if(dfn[x]==low[x]){
cnt++; size[cnt]++; belong[x]=cnt; pd[x]=;
while(Stack[top]!=x&&top) belong[Stack[top]]=cnt,pd[Stack[top]]=,top--,size[cnt]++;
top--;
}
} inline void tarjan(){
ecnt=;
for(int i=;i<=n;i++) if(!dfn[i]) dfs(i);
ecnt=;
for(int i=;i<=n;i++) {
for(int j=first[i];j;j=next[j]) {
int v=to[j];
if(belong[i]!=belong[v]) {
if(bst.find(make_pair(belong[i],belong[v]))!=bst.end()) continue;
e[++ecnt].next=head[belong[i]]; head[belong[i]]=ecnt; e[ecnt].v=belong[v];
ru[belong[v]]++;
bst.insert(make_pair(belong[i],belong[v]));
}
}
}
} inline void DFS(int x){
vis[x]=;
for(int i=head[x];i;i=e[i].next) {
int v=e[i].v;
if(!vis[v]) DFS(v);
if(f[v]>f[x]) f[x]=f[v];
}
f[x]+=size[x];
} inline void DFS2(int x){
vis[x]=;
for(int i=head[x];i;i=e[i].next) {
int v=e[i].v;
if(!vis[v]) DFS2(v);
//不能有重边!!!!!!
if(f[x]==f[v]+size[x]) { dfn[x]+=dfn[v]; if(dfn[x]>=MOD) dfn[x]%=MOD; }
}
if(!head[x]) dfn[x]=;
if(f[x]==ans) { num+=dfn[x]; if(num>=MOD) num%=MOD; }
} inline void DP(){
memset(vis,,sizeof(vis));
for(int i=;i<=cnt;i++) if(!ru[i]) DFS(i),ans=max(ans,f[i]);
memset(vis,,sizeof(vis)); memset(dfn,,sizeof(dfn));
for(int i=;i<=cnt;i++)
if(!ru[i]) {
DFS2(i);
}
printf("%d\n%d",ans,num);
} inline void work(){
n=getint(); m=getint(); MOD=getint();
int x,y;
for(int i=;i<=m;i++) {
x=getint(); y=getint();
next[++ecnt]=first[x]; first[x]=ecnt; to[ecnt]=y;
}
tarjan();
DP();
} int main()
{
work();
return ;
}

BZOJ1093 最大半连通子图的更多相关文章

  1. BZOJ1093 [ZJOI2007]最大半连通子图

    Description 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于图中任意两点u,v,存在一条u到v的有向路径或者从v到u ...

  2. bzoj1093[ZJOI2007]最大半连通子图(tarjan+拓扑排序+dp)

    Description 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于图中任意两点u,v,存在一条u到v的有向路径或者从v到u ...

  3. 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 ...

  4. 【bzoj1093】[ZJOI2007]最大半连通子图 Tarjan+拓扑排序+dp

    题目描述 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:对于u,v∈V,满足u→v或v→u,即对于图中任意两点u,v,存在一条u到v的有向路径或者从v到u的有向路径. ...

  5. BZOJ1093 [ZJOI2007]最大半连通子图 【tarjan缩点 + DAG最长路计数】

    题目 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于图中任意 两点u,v,存在一条u到v的有向路径或者从v到u的有向路径.若G ...

  6. BZOJ1093: [ZJOI2007]最大半连通子图(tarjan dp)

    题意 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于图中任意两点u,v,存在一条u到v的有向路径或者从v到u的有向路径.若G' ...

  7. 【tarjan 拓扑排序 dp】bzoj1093: [ZJOI2007]最大半连通子图

    思维难度不大,关键考代码实现能力.一些细节还是很妙的. Description 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于 ...

  8. 【bzoj1093】 [ZJOI2007]最大半连通子图

    *题目描述: 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于图中任意 两点u,v,存在一条u到v的有向路径或者从v到u的有向路 ...

  9. 最大半连通子图 bzoj 1093

    最大半连通子图 (1.5s 128MB) semi [问题描述] 一个有向图G = (V,E)称为半连通的(Semi-Connected),如果满足:∀ u, v ∈V,满足u->v 或 v - ...

随机推荐

  1. Android优化——UI优化(四) 使用stytle

    使用style替换背景,防止Activity黑色背景闪过 1.原来的布局 <LinearLayout xmlns:android="http://schemas.android.com ...

  2. docker中清理冗余的image,container

    1) 首先进入超级用户模式 [root@docker ~]# sudo su2) 删除container ( container运行时是不能删除的 )首先停止container [root@docke ...

  3. Android 界面排版的5种方式

    Android布局是应用界面开发的重要一环,在Android中,共有五种布局方式,分别是:FrameLayout(框架布局),LinearLayout (线性布局),AbsoluteLayout(绝对 ...

  4. C++ 栈的基本操作

    // zhan.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <iostream> using namesp ...

  5. 收藏所用C#技术类面试、笔试题汇总

    技术类面试.笔试题汇总 注:标明*的问题属于选择性掌握的内容,能掌握更好,没掌握也没关系. 下面的参考解答只是帮助大家理解,不用背,面试题.笔试题千变万化,不要梦想着把题覆盖了,下面的题是供大家查漏补 ...

  6. IE firefox 兼容性整理

    1.尽量用jquery操作. 2.jquery取值时要用准确的方法,attr(), val(), text(), html(). 例如: <span value="a"> ...

  7. 教你用netstat-实践案例

    netstat命令的功能是显示网络连接.路由表和网络接口信息,可以让用户得知目前都有哪些网络连接正在运作. 该命令的一般格式为: netstat [选项] 命令中各选项的含义如下: -a 显示所有so ...

  8. [bzoj 2151]种树(贪心)

    题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2151 分析:原型是bzoj 1150(CTSC 2007) 首先DP无法下手,想到贪心.想到贪 ...

  9. [c#基础]堆和栈

    前言 堆与栈对于理解.NET中的内存管理.垃圾回收.错误和异常.调试与日志有很大的帮助.垃圾回收的机制使程序员从复杂的内存管理中解脱出来,虽然绝大多数的C#程序并不需要程序员手动管理内存,但这并不代表 ...

  10. RestFul API初识

    python Restful API 微博开放平台: open.weibo.com: 点击文档进入API查看界面 点击API文档进行查看: 比如点开粉丝数的API可以看到: pro.jsonlint. ...