目录
显示
题目链接
https://www.luogu.com.cn/problem/P1477
题解
如果整个图没有环的话,显然最多能分的种类数是每个连通分量内最长链的长度之和。
如果整个图是由若干个不相交的环构成的话,最多能分的种类数是所有环长度的最大公约数(找环的时候,可以从连通块内的任意一点开始编号,第二次经过一个点的时候,它第二次的编号减去第一次的编号就是环的大小)。
除了这两种特殊情况之外,还有一种情况是两个环之间可能有公共部分。
我们 DFS 的时候可以倒推:建图的时候不仅连一条 \(u \to v\),边权为 \(1\) 的边之外,同时连一条 \(v \to u\),边权为 \(-1\) 的边(这种连边方式可以确保我们从任意一个点开始,都可以遍历整个连通块)。
对于每个连通块,我们还是任意选一个点开始编号,经过一条边的时候将编号加上边权,和上面一样,第二次经过同一个点的时候,它第二次的编号减去第一次的编号就是环的大小。
这样我们就可以找出所有的环了。
(最后别忘了题目要求面具最少要有三种)
#include <cstdio> #include <cstring> #include <algorithm> #include <set> #define INF 1e9 using namespace std; struct edge { int v,w; bool operator<(const edge&a)const { return v<a.v||(v==a.v&&w<a.w); } }; set<edge> e[100005]; int dis[100005],vis[100005],ans,res,cnt,maxv,minv; int gcd(int x,int y) { return y==0?x:gcd(y,x%y); } void dfs(int u,int d) { if(dis[u]) { ans=gcd(ans,abs(d-dis[u])); return; } dis[u]=d,vis[u]=1; maxv=max(maxv,dis[u]); minv=min(minv,dis[u]); for(auto i:e[u]) dfs(i.v,d+i.w); } int main() { int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { int u,v; scanf("%d%d",&u,&v); e[u].insert({v,1}); e[v].insert({u,-1}); } for(int i=1;i<=n;i++) if(!vis[i]) { maxv=-INF,minv=INF; dfs(i,1); res+=maxv-minv+1; } if(ans) { if(ans<3)puts("-1 -1"); else for(int i=3;i<=ans;i++) if(ans%i==0) { printf("%d %d\n",ans,i); break; } } else { if(res<3)puts("-1 -1"); else printf("%d 3\n",res); } return 0; }