BZOJ 4116 Wf2015 Tours Tarjan

题目大意:给定一张n个点m条边的无向图,你需要选择一个颜色种类数k,然后用这k种颜色给每条边染色,要求对于图中任意一个简单环,每种颜色的边的数量都相同,求所有可行的k

考虑将边集E拆成一些子集{E1,E2,E3,..},满足任意一个简单环可以被拆成一些子集的和,且不存在两个子集合并后仍满足条件,那么答案就是gcd{|E1|,|E2|,|E3|,..}的所有约数

那么如何确定这些子集呢?

“尝试删掉每一条非桥边并统计有多少边成为了新的桥边。得到的数+1的gcd。”——Petr

Tourist刷了下推特,嘴角随之露出了一抹神秘的、带着战斗民族气息的微笑。(巨雾

我们尝试删掉每一条非桥边,那么新成为桥的边一定和这条非桥边属于同一个集合,然而我并不会证明。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 2020
using namespace std;
struct edge{
    int x,y;
}edges[M];
struct abcd{
    int to,num,next;
}table[M<<1];
int head[M],tot=1;
int n,m,ans;
int dpt[M],low[M],T;
bool is_bridge[M],to_be_bridge[M],v[M];
void Initialize()
{
    memset(head,0,sizeof head);
    tot=1;
    memset(dpt,0,sizeof dpt);
    memset(low,0,sizeof low);
    memset(to_be_bridge,0,sizeof to_be_bridge);
}
void Add(int x,int y,int z)
{
    table[++tot].to=y;
    table[tot].num=z;
    table[tot].next=head[x];
    head[x]=tot;
}
void Tarjan(int x,int from)
{
    int i;
    dpt[x]=low[x]=++T;
    for(i=head[x];i;i=table[i].next)
        if(i^from^1)
        {
            if(dpt[table[i].to])
                low[x]=min(low[x],dpt[table[i].to]);
            else
            {
                Tarjan(table[i].to,i);
                low[x]=min(low[x],low[table[i].to]);
                if(low[table[i].to]>dpt[x])
                    to_be_bridge[table[i].num]=true;
            }
        }
}
int main()
{
    int i,j;
    cin>>n>>m;
    for(i=1;i<=m;i++)
    {
        scanf("%d%d",&edges[i].x,&edges[i].y);
        Add(edges[i].x,edges[i].y,i);
        Add(edges[i].y,edges[i].x,i);
    }
    for(i=1;i<=n;i++)
        if(!dpt[i])
            Tarjan(i,0);
    memcpy(is_bridge,to_be_bridge,sizeof is_bridge);
    for(i=1;i<=m;i++)
        if(!v[i]&&!is_bridge[i])
        {
            int cnt=1;
            v[i]=true;
            Initialize();
            for(j=1;j<=m;j++)
                if(j!=i)
                {
                    Add(edges[j].x,edges[j].y,j);
                    Add(edges[j].y,edges[j].x,j);
                }
            for(j=1;j<=n;j++)
                if(!dpt[j])
                    Tarjan(j,0);
            for(j=1;j<=m;j++)
                if(!is_bridge[j]&&to_be_bridge[j])
                    v[j]=true,++cnt;
            ans=__gcd(ans,cnt);
        }
    for(i=1;i<=ans;i++)
        if(ans%i==0)
            printf("%d%c",i,i==ans?‘\n‘:‘ ‘);
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-03 16:38:14

BZOJ 4116 Wf2015 Tours Tarjan的相关文章

BZOJ 4116[WorldFinal2015]Tours

题面: 4116: [Wf2015]Tours Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 129  Solved: 46[Submit][Status][Discuss] Description 给定一张n个点m条边的无向图,你需要选择一个颜色种类数k,然后用这k种颜色给每条边染色,要求对于图中任意一个简单环,每种颜色的边的数量都相同,求所有可行的k Input 第一行两个正整数n,m 接下来m行,每行两个正整数x,y(1<=x<y<=

[Wf2015]Tours

[Wf2015]Tours 题目 给定一张n个点m条边的无向图,你需要选择一个颜色种类数k,然后用这k种颜色给每条边染色,要求对于图中任意一个简单环,每种颜色的边的数量都相同,求所有可行的k INPUT 第一行两个正整数n,m接下来m行,每行两个正整数x,y(1<=x<y<=n),代表一条无向边数据保证无重边无自环 OUTPUT 一行输出所有可行的k,按递增顺序输出 6 6 1 2 2 3 1 3 1 4 2 5 3 6 SAMPLE INPUT 6 6 1 2 2 3 1 3 1 4

[BZOJ 1179]ATM题解 Tarjan缩点+SPFA

[BZOJ 1179]ATM题解 Tarjan缩点+SPFA Description Input 第一行包含两个整数N.M.N表示路口的个数,M表示道路条数.接下来M行,每行两个整数,这两个整数都在1到N之间,第i+1行的两个整数表示第i条道路的起点和终点的路口编号.接下来N行,每行一个整数,按顺序表示每个路口处的ATM机中的钱数.接下来一行包含两个整数S.P,S表示市中心的编号,也就是出发的路口.P表示酒吧数目.接下来的一行中有P个整数,表示P个有酒吧的路口的编号 Output 输出一个整数,

BZOJ 1179: [Apio2009]Atm( tarjan + 最短路 )

对于一个强连通分量, 一定是整个走或者不走, 所以tarjan缩点然后跑dijkstra. --------------------------------------------------------------------- #include<bits/stdc++.h> #define rep(i, n) for(int i = 0; i < n; ++i) #define clr(x, c) memset(x, c, sizeof(x)) #define foreach(i,

bzoj 1179[Apio2009]Atm (tarjan+spfa)

题目 输入 第一行包含两个整数N.M.N表示路口的个数,M表示道路条数.接下来M行,每行两个整数,这两个整数都在1到N之间,第i+1行的两个整数表示第i条道路的起点和终点的路口编号.接下来N行,每行一个整数,按顺序表示每个路口处的ATM机中的钱数.接下来一行包含两个整数S.P,S表示市中心的编号,也就是出发的路口.P表示酒吧数目.接下来的一行中有P个整数,表示P个有酒吧的路口的编号 输出 输出一个整数,表示Banditji从市中心开始到某个酒吧结束所能抢劫的最多的现金总数. 样例输入 6 7 1

BZOJ4116 : [Wf2015]Tours

将边集划分成若干极大不相交集合,满足每个简单环都可以由某些集合相加得到,则答案就是这些集合大小的$\gcd$的约数. 对于一个简单环,上面的边一定不是桥边,而和它在一个集合的边肯定不在其他简单环上.因此删除它之后,这些边就从非桥边变成了桥边. 枚举每条非桥边跑Tarjan计算答案即可. 时间复杂度$O(m(n+m))$. #include<cstdio> const int N=2005,BUF=21000; int n,m,i,x,y,now,ans,D,cut[N],g[N],v[N<

BZOJ 2208 JSOI2010 连通数 Tarjan+拓扑排序

题目大意:给定一个n个点的有向图,求有多少点对(x,y),使x沿边可到达y 设f[i][j]为从i到j是否可达 首先强联通分量中的任意两个点均可达 于是我们利用Tarjan缩点 缩点之后是一个拓扑图,我们求出拓扑序,沿着拓扑序从后向前DP,状态转移方程为: f[i][k]=or{ f[j][k] } (i有直连边到达j,1<=k<=n,n为强连通分量的个数) 鉴于每个点的值只会是1或者0,所以我们可以直接状压,或者干脆开bitset,整体取或即可 时间复杂度O(mn/32) 今天各种手滑...

蒟蒻刷题记~ Week 1-2

Week 1[11.10-11.16] NOIP挂了嘛,于是也开始了新一轮虐(bei)题(nve)QAQ 冒着下周期中考的大难... [BZOJ 1005]Purfer Sequence+数论·组合 [BZOJ 1007]数论·平面几何 [BZOJ 1009]KMP+DP+DP优化·矩阵快速幂 [BZOJ 1003]小数据暴力+最短路+DP [BZOJ 1016]树论·MST [BZOJ 1006]图论·最小染色 [BZOJ 1013]数论·高斯消元法 [BZOJ 1015]数据结构·并查集+图

bzoj 1023: [SHOI2008]cactus仙人掌图 tarjan索环&amp;&amp;环上单调队列

1023: [SHOI2008]cactus仙人掌图 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 1141  Solved: 435[Submit][Status] Description 如果某个无向连通图的任意一条边至多只出现在一条简单回路(simple cycle)里,我们就称这张图为仙人图(cactus).所谓简单回路就是指在图上不重复经过任何一个顶点的回路. 举例来说,上面的第一个例子是一张仙人图,而第二个不是——注意到它有三条简单回路