如果没有环那么最大的面具的种类为所有联通块最长链之和、最小为3,如果最长链之和<3,则无解;
如果有环找出每个环的结点个数=、=面具种类数为所有环的结点个数的最大公约数x。
为什么呢
一个环1->2,2->3,3->4,4->5,5->6,6->1;那么可能的面具数为6或3种,是6的约数。
如果公约数小于3无解,大于3有解,最小的面具种数一定是>=3,<=x的一个x的约数。
那么最长链怎么求呢?
3->2->1->4->5;
如果枚举的话第一个是1,要求到最长链要枚举到3。。。。我们可以建立边的时候1->4这条边分为1->4为权值为1的边,4->1为权值为-1的边。那么枚举到1时,从1开始dfs,求每个点的dis,dis[3] = -2,dis[5] = 2;那么最长链的大小为dis[5] - dis[3] + 1;即遍历一次,最大的dis - 最小的dis +1;
那么环的个数怎么求呢?
tarjian?不行啊比如1->2->3.然而还有1->3这条边,然而这是个环,按以上建图法,tarjian回把它算为一个大小为3的环。。。然而这个环是不合法的。。。。所以我们采用dfs,如果没点v遍历过更新dis,如果遍历过环的大小为abs(dis[x] + tow - dis[v])(v是从x变了过来的,x->v这条边的边权为tow; )
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int n, m;
int tov[2000005],h[100005],tp, nex[2000005], tow[2000005];
int vis[100005], dis[100005], ma, vis1[100005], maa, mii,dis1[100005];
void read(int &x)
{
x = 0;
char c = getchar();
while(c < '0' || c > '9')
{
c = getchar();
}
while( c >= '0' && c <= '9')
{
x = 10 * x + c -'0';
c = getchar();
}
}
int gcd(int n, int m)
{
if(m == 0) return n;
return gcd(m, n%m);
}
void add(int x,int y,int w)
{
tp ++;
nex[tp] = h[x];
tow[tp] = w;
h[x] = tp;
tov[tp] = y;
}
void dfs(int x, int fa)
{
for(int i = h[x]; i; i = nex[i])
{
int v = tov[i];
if(v == fa) continue;
if(vis[v] == 1)
{
int ha = dis[v] - (dis[x] + tow[i]);
if(ha < 0) ha = (-1) * ha;
if(ma == 0) ma = ha;
else
{
if(ha != 0)
{
ma = gcd(ma,ha);
}
}
}
else
{
vis[v] = 1;
dis[v] = dis[x] + tow[i];
dfs(v,x);
}
}
}
void dfs1(int x, int fa)
{
for(int i = h[x]; i; i = nex[i])
{
int v = tov[i];
if(vis1[v] == 1 || v == fa) continue;
maa = max(maa , dis1[x] + tow[i]);
mii = min(mii , dis1[x] + tow[i]);
dis1[v] = dis1[x] + tow[i];
vis1[v] = 1;
dfs1(v,x);
}
}
int main()
{
read(n);
read(m);
for(int i = 1; i <= m; i++)
{
int x,y;
read(x);
read(y);
add(x,y,1);
add(y,x,-1);
}
for(int i = 1; i <= n; i++)
{
if(vis[i] == 0)
{
vis[i] = 1;
dfs(i,i);
}
}
if(ma == 0)
{
int zm = 0;
for(int i = 1; i <= n; i++)
{
if(vis1[i] == 0)
{
maa = 0, mii = 0;
vis1[i] = 1;
dfs1(i,i);
zm = zm + (maa - mii + 1);
}
}
if(zm < 3)
{
printf("-1 -1");
return 0;
}
printf("%d 3",zm);
}
else
{
if(ma < 3)
{
printf("-1 -1");
return 0;
}
int mi = 0;
for(int i = 3; i <= ma; i++)
{
if(ma % i == 0)
{
mi = i;
break;
}
}
printf("%d %d",ma,mi);
}
return 0;
}