动漫节一游回来之后一直处于一种意识模糊的状态

看到大家都陆陆续续地过了C心里还是有点着急(自己没思路啊囧)

其实当时就在想该如何找到DFS中的一个环,然后再找到环路上最小的一个值

把所有环路上最小的值加起来就是结果,后来看到有人在群里说是tarjan求强连通分量,我就愉(bei)快(shang)地去睡觉了

第二天起来就学习了一下强连通分量的相关知识和tarjan,现在整理下思路

https://www.byvoid.com/blog/scc-tarjan

tarjan的思路就是通过DFS找到一条环路,将以DFS访问的顺序的节点盖上时间戳,当该点u时间戳与该点(直接或间接)能够访问到的最早入栈的点相同(即可以说成是自身就是该子树的根)时,即表示它就是一个强连通量的根节点。我们不妨直接找到树中的一个“叶子”(姑且这么叫吧,把这里的“叶子”定义为除了栈S中的节点不能到达其他任何节点的节点(好绕囧))节点v,那么它只有两种可能:

1.可以在未处理节点的栈S中找到一个V使得(v,V)∈E,因此可以由V出发到v构成一个环路

2.不可以在未处理节点的栈S中找到一个V使得(v,V)∈E,因此它自成一个强连通分量(因为它不能到达任何的节点)(上述称为判断1)

如果讨论清楚了“叶子”节点,它必然成为某一个强连通分量中的一个顶点;再讨论栈中v的上一个节点u(即(u,v)∈E,且u∈栈S)

1.若为上述情况1,则根据上述链接和大白书上的定理,u,v必在同一个强连通分量中

2.若为上述情况2,则可以通过DFS找到u的其他后继vi:

  (1)若vi存在,则继续用判断1判断有后继(祖先)在S中

(2)若vi不存在,则说明u没有其他后继了(自然也没有在栈S中的后继),则u可以通过上述情况2,u自成一个强连通分量

至此,证明完毕。可以保证,在栈S中的节点必然是以U为根“最大”(不知道这样说准不准确)的强连通量(因为不满足的已经被标记上强连通序号且弹出栈了)。

此说明是基于所有不属于以U为根的强连通分量的顶点已经被标记且弹出栈了。

上述描述即是以DFS序来进行描述的。

OK,回到这道题,如果找到了一个强连通分量,则可以统计出它的最小权值和最小权值点的个数

总的方案数就是所有强连通分量中的最小权值点个数的乘积

下面是C题的程序

#include<cstdio>
#include<cstring>
#include<stack>
#include<algorithm>
using namespace std;
typedef long long LL;
const int SIZEN=100005;
const int SIZEM=300005;
const int INF=1e9;
const int MOD=1e9+7;
struct edge{
int to,next;
};
edge e[SIZEM];
int cost[SIZEN],head[SIZEN];
int DFN[SIZEM],low[SIZEN],sscn[SIZEN];
LL sz,s_cost,num_cost,dfs_time,ssc_cnt;
void addedge(int u,int v){
e[sz].to=v;
e[sz].next=head[u];
head[u]=sz++;
}
void init(){
memset(DFN,0,sizeof(DFN));
memset(low,0,sizeof(low));
memset(sscn,0,sizeof(sscn));
memset(head,-1,sizeof(head));
sz=0;num_cost=1;s_cost=0;
dfs_time=1;ssc_cnt=0;
}
stack<int> S;
void tarjan(int u){
DFN[u]=low[u]=dfs_time++;
S.push(u);
for(int i=head[u];i!=-1;i=e[i].next){
int v=e[i].to;
if(!DFN[v]){
tarjan(v);
low[u]=min(low[u],low[v]);//回溯过程,如果low[v]<low[u],则必然是因为v的某子孙和u的某祖先相连
}
else if(DFN[v]&&!sscn[v]){
low[u]=min(low[u],DFN[v]);//即上述判断1的情况1(找到后继在S中)
}
}
if(DFN[u]==low[u]){//找到一个强连通分量,找到分量中的最小值,和最小值的个数
int x;
int Min=INF,cnt=0;
ssc_cnt++;
for(;;){
x=S.top();S.pop();
sscn[x]=ssc_cnt;
if(cost[x]<Min){
Min=cost[x];
cnt=1;
}
else if(cost[x]==Min) cnt++;
if(x==u) break;
}
s_cost=s_cost+Min;num_cost=(LL)num_cost*cnt%MOD;
}
}
int main()
{
//freopen("data.in","r",stdin);
int i,j;
int n,m;
int u,v;
while(scanf("%d",&n)!=EOF){
init();
for(i=1;i<=n;i++) scanf("%d",&cost[i]);
scanf("%d",&m);
while(m--){
scanf("%d%d",&u,&v);
addedge(u,v);
}
for(i=1;i<=n;i++)
if(!DFN[i]) tarjan(i);
printf("%I64d %I64d\n",s_cost,num_cost);
}
return 0;
}

codeforces#244(div.2) C的更多相关文章

  1. codeforces 338(Div 2) B. Longtail Hedgehog 解题报告

    题目链接:http://codeforces.com/problemset/problem/615/B 题目意思:要画一只 hedgehog,由 tail 和 spines 组成.我们要求得 beau ...

  2. Codeforces Round #581(Div. 2)

    Codeforces Round #581(Div. 2) CF 1204 A. BowWow and the Timetable 题解:发现,$4$的幂次的二进制就是一个$1$后面跟偶数个$0$. ...

  3. Codeforces Round #433 (Div. 2)【A、B、C、D题】

    题目链接:Codeforces Round #433 (Div. 2) codeforces 854 A. Fraction[水] 题意:已知分子与分母的和,求分子小于分母的 最大的最简分数. #in ...

  4. 10-2 body标签中相关的标签(字体标签,排版标签(div,span),超链接,图片标签)

    一 排版标签(div,span) 1块级标签 <!--div:把标签中的内容作为一个块儿来对待(division).必须单独占据一行.--> <!--div标签的属性:--> ...

  5. 【CodeForces】841D. Leha and another game about graph(Codeforces Round #429 (Div. 2))

    [题意]给定n个点和m条无向边(有重边无自环),每个点有权值di=-1,0,1,要求仅保留一些边使得所有点i满足:di=-1或degree%2=di,输出任意方案. [算法]数学+搜索 [题解] 最关 ...

  6. Codeforces Round #334(div.2)(新增不用二分代码) B

    B. More Cowbell time limit per test 2 seconds memory limit per test 256 megabytes input standard inp ...

  7. Vus the Cossack and Strings(Codeforces Round #571 (Div. 2))(大佬的位运算实在是太强了!)

    C. Vus the Cossack and Strings Vus the Cossack has two binary strings, that is, strings that consist ...

  8. 网站常见问题及解决方法(div/css)

    18.<a> 在IE6,7 下面重新定义宽和高的代码:{  display:block; display:-moz-inline-stack; display:inline-block;  ...

  9. CodeForces - 589A(二分+贪心)

    题目链接:http://codeforces.com/problemset/problem/589/F 题目大意:一位美食家进入宴会厅,厨师为客人提供了n道菜.美食家知道时间表:每个菜肴都将供应. 对 ...

随机推荐

  1. sql server 用触发器记录增删改操作(转载)

    数据库结构: CREATE TABLE [dbo].[cg_tz_log] ( [logid] int NOT NULL IDENTITY(1,1) , operate varchar(10), -- ...

  2. Sentinel限流之快速失败和漏桶算法

    距离上次总结Sentinel的滑动窗口算法已经有些时间了,原本想着一口气将它的core模块全部总结完,但是中间一懒就又松懈下来了,这几天在工作之余又重新整理了一下,在这里做一个学习总结. 上篇滑动窗口 ...

  3. 【JDBC核心】commons-dbutils

    commons-dbutils 简介 commons-dbutils 是 Apache 组织提供的一个开源 JDBC 工具类库,它是对 JDBC 的简单封装,学习成本极低,并且使用 commons-d ...

  4. 按装parallels tool的失败之路

    这是一篇对于其他人来说没什么意义的博客.单纯的可以被看作是日记. 首先,我想安装parallels tool. 但是照着网上很多教程(如www.cnblogs.com/artwalker/p/1323 ...

  5. Docker 介绍和安装(一)

    # 下载阿里云的 Centos7 的docker.repo # step 1: 安装必要的一些系统工具 sudo yum install -y yum-utils device-mapper-pers ...

  6. windows下的:开始→运行→命令

    开始→运行→命令 集锦                          winver---------检查Windows版本wmimgmt.msc----打开windows管理体系结构(WMI)wu ...

  7. 微服务网关1-Spring Cloud Gateway简介

    一.网关基本概念 1.API网关介绍 ​ API 网关出现的原因是微服务架构的出现,不同的微服务一般会有不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各 ...

  8. Django Signals

    信号 Django中提供了"信号调度",用于在框架执行操作时解耦.通俗来讲,就是一些动作发生的时候,信号允许特定的发送者去提醒一些接受者. Django内置的信号 Model si ...

  9. Crunch

    Crunch 目录 1. 简介 2. 命令格式 3. options可选参数 3.1 -b number[type] 3.2 -c number 3.3 -d numbersymbol 3.4 -e ...

  10. code-server Command ' ' not found

    由于通过一些特殊的方式登录linux用户后,全局变量不会自动加载,需要在 vscode 的 bash terminal手动读取 输入 source /etc/profile 或者vim ~/.bash ...