分享web开发知识

注册/登录|最近发布|今日推荐

主页 IT知识网页技术软件开发前端开发代码编程运营维护技术分享教程案例
当前位置:首页 > 软件开发

LOJ-1308-Ant network(蚂蚁的网络)-求割点分隔开的子图个数及乘积

发布时间:2023-09-06 01:44责任编辑:赖小花关键词:暂无标签

网上的题解大都模糊,我可能写的也比较模糊吧,讲究看看。

大致题意:

  原图没有一个割点时,特殊考虑,至少ans1=2个通风井,方案数n*(n-1)/2;

       原图上有多个割点时,每个(由割点限制成几部分的)联通块个数即为ans1;需要dfs进行vis标记和iscut区分,不重不漏;

       ans2,建设时避开在割点上建设通风井(通风井数量可最小化,以免通风井损毁后还需再建一个以备万一);求解时:当一个颜色块有两个割点时,摧毁一个蚂蚁们总可以通过另一个割点紧急转移;当一个颜色块有仅一个割点时,摧毁割点后就必须在颜色块内部建设一个。

  //五点双环一割点,(发现这个样例:颜色块为1割点不为1,用颜色块来计算就不对头了!)

  12    

  5  6  0  1  1  2  0  2  2   3   2  4   3   4

AC题解:

//头文件都私奔了!#include<set>using namespace std;#define N 10100#define inf 0x3f3f3f3ftypedef unsigned long long ULL;int n,m,Time; ??//单指向边的共m条;vector<int>G[N]; ???///一次存贮1个内存!!int dfn[N],low[N];int color_num,in[N];stack<int>st;int father[N];int cas;int color[N]; ??///表示i在的颜色块的编号,本题无用!bool iscut[N]; ?????///表示i 是否为割点bool vis[N]; ??///dfs中有用int test_num; ?///dfs中从某u点(非割点)出发可以遇见的set<int>ss; ///从某u点(非割点)出发dfs中的遇见割点(方便去重用set)ULL mod;///模数void init(){ ???for(int i=0;i<=n;i++){ ???????G[i].clear(); ???} ???memset(dfn,0,sizeof(dfn)); ???memset(low,0,sizeof(low)); ???Time=0; ???color_num=0; ???memset(in,0,sizeof(in));memset(color,0,sizeof(color)); ???memset(iscut,false,sizeof(iscut)); ???memset(father,-1,sizeof(father)); ???while(!st.empty())st.pop();}void tarjan(int u,int fa){ ???dfn[u]=low[u]=++Time; ???st.push(u);in[u]=1; ???father[u]=fa; ??///别忘记! ???for(int i=0;i<(int)G[u].size();i++){ ???????int v=G[u][i]; ???????if(!dfn[v]){ ???????????tarjan(v,u); ???????????low[u]=min(low[u],low[v]); ???????} ???????else if(v!=fa&&in[u]==1){ ?///子节点在队列中并且不是父节点 ???????????low[u]=min(low[u],dfn[v]); ???????} ???} ???if(dfn[u]==low[u]){ ???????++color_num; ???????int top; ???????do{ ???????????top=st.top();st.pop(); ???????????in[top]=0; ???????????color[top]=color_num; ??//细节! ???????}while(top!=u); ???}}ULL fact_mod(ULL x){ ??///对2的64次方取模(mod只有一半) ???while(x/(ULL)2>=mod) ???????x=x-mod-mod; ???return x;}void dfs(int u){ ???vis[u]=1; ???test_num++; ??///从u点出发的由割点分隔开的联通图中的非割点数目 ???for(int i=0;i<(int)G[u].size();i++){ ???????int v=G[u][i]; ???????if(iscut[v]){ ???????????ss.insert(v);continue; ???????} ???????if(iscut[v]||vis[v])continue; ??///vis防重复,iscut防dfs到切点 ???????dfs(v); ???}}void solve() ??//缩点{ ???tarjan(0,-1); ?///单源点图,求DAG ???int ans1=0; ???ULL ans2=1; ???int rootsons=0,u,cnt=0; ?///cnt表示割点个数 ???for(int i=0;i<n;i++){ ??///求割点,分类特判源点0是否为割点 ???????if(father[i]==0) ???????????rootsons++; ???????else{ ???????????u=father[i]; ///父节点 ???????????if(dfn[u]<=low[i]&&iscut[u]==false){ ???????????????iscut[u]=true;cnt++; ???????????} ???????} ???} ???if(rootsons>1){ ??///特判源点 ???????iscut[0]=true;cnt++; ???} ???if(cnt==0){ ?///没有割点的图 ???????ans1=2; ???????ans2=(ULL)n*(n-1)/2; ???????ans2=fact_mod(ans2); ???} ???else{ ???????memset(vis,false,sizeof(vis)); ???????for(int i=0;i<n;i++){ ??///多个割点的图 ???????????if(iscut[i]||vis[i]) ???????????????continue; ???????????ss.clear();test_num=0; ???????????dfs(i); ???????????if(ss.size()<=1){ ???????????????ans1++;ans2=ans2*(ULL)test_num; ???????????} ???????} ???} ???ans2=fact_mod(ans2); ???printf("Case %d: %d %llu\n",++cas,ans1,ans2);}int main(){ ???int T; ???scanf("%d",&T); ???cas=0; ???mod=(ULL)1; ?///求模数 ???for(int i=1;i<=63;i++){ ????????mod=mod*(ULL)2; ???} ???while(T--){ ???????scanf("%d%d",&n,&m); ???????init(); ???????int x,y; ???????for(int i=1;i<=m;i++){ ???????????scanf("%d%d",&x,&y); ???????????G[x].push_back(y); ???????????G[y].push_back(x); ???????} ???????solve(); ???} ???return 0;}
View Code

LOJ-1308-Ant network(蚂蚁的网络)-求割点分隔开的子图个数及乘积

原文地址:https://www.cnblogs.com/zhazhaacmer/p/8497004.html

知识推荐

我的编程学习网——分享web前端后端开发技术知识。 垃圾信息处理邮箱 tousu563@163.com 网站地图
icp备案号 闽ICP备2023006418号-8 不良信息举报平台 互联网安全管理备案 Copyright 2023 www.wodecom.cn All Rights Reserved