手铐-牛客(tarjan+dfs)
时间:2020-08-08
本文章向大家介绍手铐-牛客(tarjan+dfs),主要包括手铐-牛客(tarjan+dfs)使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
给你一个连通无向图,保证每个点最多属于一个简单环,每个点度数最多为3,求这个图有多少“手铐图形个数”
其中“手铐图形个数”,定义为三元组(x,y,S),其中x和y表示图上的两个点,S表示一条x到y的简单路径,而且必须满足:
1.x和y分别在两个不同的简单环上
2.x所在的简单环与路径S的所有交点仅有x,y所在的简单环与路径S的所有交点仅有y。
(x,y,S)与(y,x,S)算同一个手铐;原图:
假设在两个方点之间有x个方点,则构成的手铐数量为2^x;
考虑u的所有子树中点数超过1(方点)的块走到u的方案数dp[u],以此考虑u的儿子,对于第一个儿子v,若u也是点大于1的块,那么第一个儿子中点数大于1的点到u构成的手铐对答案的贡献就是dp[v],对于其他儿子,可以经过u点与之前考虑的儿子中点数大于1的点构成手铐,此时对答案的贡献就是dp[u]⋅dp[v]。
对于dp[u]的维护,如果u点数大于1,那么dp[u]+=2⋅dp[v],否则dp[u]+=dp[v],时间复杂度O(n+m)
将节点当成半手铐看;dp[u]表示以u为父节点的半手铐数量
1,圆形节点 dp[u]+=dp[v];
2,方形节点 dp[u]+=dp[v]*2;
ans[u]表示以u为父节点的手铐数,v是子节点;
#include<bits/stdc++.h> /*#include<iostream> #include<string> #include<cstdio> #include<algorithm> #include<cmath> #include<iomanip> #include<queue> #include<cstring>*/ using namespace std; const int maxn=1e6+10; const int mod=19260817; const int inf=0x3f3f3f3f; typedef long long ll; typedef pair<int,int> pii; const int N=5e5+10; inline int read() { int x=0,w=0; char ch=getchar(); while (!isdigit(ch)) w|=ch=='-',ch=getchar(); while (isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar(); return w?-x:x; } struct node{ int v,next; }G[maxn<<2]; int head[maxn<<1],cnt; inline void add(int x,int y) { G[cnt]=(node){y,head[x]}; head[x]=cnt++; } int dfn[maxn],low[maxn],tot; stack<int> st; //int Stack[maxn],top; int vis[maxn]; int belong[maxn]; int num; ll f[maxn]; int cot[maxn]; void tarjan(int u,int pre) { dfn[u]=low[u]=++tot; st.push(u); vis[u]=1; for(int i=head[u]; i!=-1; i=G[i].next) { if(G[i].v==pre) continue; int v=G[i].v; if(!dfn[v]) { tarjan(v,u); low[u]=min(low[u],low[v]); } else if(vis[v]) low[u]=min(low[u],dfn[v]); } if(dfn[u]==low[u]) { ++num; int t; do{ t=st.top(); st.pop();//缩点 ++cot[num];//判断方点还是圆点 vis[t]=0; belong[t]=num;//t属于num所代表的节点 }while(u!=t); } } ll dp[maxn]; vector <int> g[maxn]; //ll tmp[maxn]; void dfs(int u,int fa)//当前节点,父节点 { dp[u]=0;//初始值 f[u]=(cot[u]>1);//1.0标记圆方点 for(int v:g[u]) { //int v=G[i].v; if(v==fa) continue;//与u相连的节点是父节点跳过这个点,剪枝 dfs(v,u); dp[u]=(1ll*dp[u]+f[v]*f[u]+dp[v])%mod;//计算手铐数 f[u]=(1ll*f[u]+f[v]*(cot[u]>1?2:1))%mod; //f[u]=f[u]>1; f[u]=(1ll*f[u]+f[v]*(f[u]==1?2:1))%mod;过不了 //f[u]的值一直在变化,如果不分开存储,会出现问题。 } } int n,m; int main() { n=read(),m=read(); for(int i=0; i<=n; i++) head[i]=-1; for(int i=1; i<=m; i++) { int u,v; u=read(),v=read(); add(u,v); add(v,u); } for(int i=1; i<=n; i++) { if(!dfn[i]) tarjan(i,0);//缩点 } for(int i=1; i<=n; i++)//构造新图 { for(int j=head[i]; j!=-1; j=G[j].next) { int u=belong[i],v=belong[G[j].v]; if(u!=v) g[u].push_back(v); } } dfs(1,0); cout<<dp[1]<<endl;//答案 system("pause"); return 0; }
原文地址:https://www.cnblogs.com/sweetlittlebaby/p/13460600.html
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Laravel 前端资源配置教程
- laravel框架语言包拓展实现方法分析
- PHP使用JpGraph绘制折线图操作示例【附源码下载】
- Laravel Eloquent分表方法并使用模型关联的实现
- 关于laravel模板中生成URL的几种模式总结
- Laravel基础-关于引入公共文件的两种方式
- Laravel框架Blade模板简介及模板继承用法分析
- 基于Laravel 多个中间件的执行顺序详解
- 关于laravel 日志写入失败问题汇总
- 确保Laravel网站不会被嵌入到其他站点中的方法
- PHP PDO和消息队列的个人理解与应用实例分析
- tp5 sum某个字段相加得到总数的例子
- laravel框架创建授权策略实例分析
- tp5递归 无限级分类详解
- PHP 进程池与轮询调度算法实现多任务的示例代码