一道很是神奇的图论题解法无比新奇清新git
咱们首先把图分红三种状况:spa
很容易发现,最后一种状况想怎么取就怎么取,那么咱们只须要考虑1,2的影响便可code
可是若是咱们傻乎乎地直接跑好像也是能够的那就太烦了。blog
咱们考虑这样的一个图:string
咱们把原图中的边分红两类:红色(顺时针)和绿色(逆时针)。而后咱们发现这种图对应上面讲的状况2。而后手推颜色发现要两种。it
而这个2是怎么来的,很简单,\(color=| total_{red}-total_{green} |\)。为何,咱们仔细观察一下对于每个被一条顺时针边和一条逆时针边链接的点,与它相连的点颜色必定相同io
而后咱们就能够把问题转化成无向边并找环了。可是图中的边并无顺时针/逆时针,因而咱们分红正向边/反向边考虑便可。class
能够设为相反的边权(如\(1 \&\& -1\)等)。而后取绝对值便可。gc
而后对于有环的状况(不管时1仍是2),咱们均可以得出\(ans=gcd(|len|)\),其中\(len\)表示环长,那么最小值就是\(min(ans|u)\)im
值得注意的还有森林的状况,稍加推到此时的\(ans=\sum maxdis-mindis+1 \ (for\ each\ Unicom\ blocks\ of \ the\ gragh)\)
最后当获得的\(ans<3\)时无解。找环固然是BFS/DFS了(注意不要把环和SCC搞混了)
BFS版CODE
#include<cstdio> #include<cctype> #include<cstring> using namespace std; const int N=100005,M=1000005; struct edge { int to,next,v; }e[M<<1]; int head[N],dis[N],q[N],n,m,x,y,ans,lans,sum,cnt,MIN,MAX; bool vis[N]; inline char tc(void) { static char fl[100000],*A=fl,*B=fl; return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++; } inline void read(int &x) { x=0; char ch; while (!isdigit(ch=tc())); while (x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc())); } inline void double_add(int x,int y) { e[++cnt].to=y; e[cnt].v=1; e[cnt].next=head[x]; head[x]=cnt; e[++cnt].to=x; e[cnt].v=-1; e[cnt].next=head[y]; head[y]=cnt; } inline int gcd(int n,int m) { return m?gcd(m,n%m):n; } inline int min(int a,int b) { return a<b?a:b; } inline int max(int a,int b) { return a>b?a:b; } inline void BFS(int s) { register int i,H=0,T=1; vis[s]=1; q[1]=s; while (H<T) { int now=q[++H]; for (i=head[now];~i;i=e[i].next) if (vis[e[i].to]) ans=gcd(ans,dis[now]-dis[e[i].to]+e[i].v); else { dis[e[i].to]=dis[now]+e[i].v; vis[e[i].to]=1; q[++T]=e[i].to; MIN=min(MIN,dis[e[i].to]); MAX=max(MAX,dis[e[i].to]); } } } int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); register int i; read(n); read(m); memset(head,-1,sizeof(head)); memset(e,-1,sizeof(e)); for (i=1;i<=m;++i) read(x),read(y),double_add(x,y); for (i=1;i<=n;++i) if (!vis[i]) { MAX=MIN=0; BFS(i); sum+=MAX-MIN+1; } if (ans<0) ans=-ans; if (ans) { if (ans<3) return puts("-1 -1"),0; for (lans=3;lans<ans&&ans%lans;++lans); return printf("%d %d",ans,lans),0; } if (sum<3) return puts("-1 -1"),0; return printf("%d 3",sum),0; }
DFS版CODE
#include<cstdio> #include<cctype> #include<cstring> using namespace std; const int N=100005,M=1000005; struct edge { int to,next,v; }e[M<<1]; int head[N],dis[N],n,m,x,y,ans,lans,sum,cnt,MIN,MAX; bool vis[N]; inline char tc(void) { static char fl[100000],*A=fl,*B=fl; return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++; } inline void read(int &x) { x=0; char ch; while (!isdigit(ch=tc())); while (x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc())); } inline void double_add(int x,int y) { e[++cnt].to=y; e[cnt].v=1; e[cnt].next=head[x]; head[x]=cnt; e[++cnt].to=x; e[cnt].v=-1; e[cnt].next=head[y]; head[y]=cnt; } inline int gcd(int n,int m) { return m?gcd(m,n%m):n; } inline int min(int a,int b) { return a<b?a:b; } inline int max(int a,int b) { return a>b?a:b; } inline void DFS(int now) { register int i; vis[now]=1; for (i=head[now];~i;i=e[i].next) if (vis[e[i].to]) ans=gcd(ans,dis[now]-dis[e[i].to]+e[i].v); else MIN=min(MIN,dis[e[i].to]=(dis[now]+e[i].v)),MAX=max(MAX,dis[e[i].to]),DFS(e[i].to); } int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); register int i; read(n); read(m); memset(head,-1,sizeof(head)); memset(e,-1,sizeof(e)); for (i=1;i<=m;++i) read(x),read(y),double_add(x,y); for (i=1;i<=n;++i) if (!vis[i]) { MAX=MIN=0; DFS(i); sum+=MAX-MIN+1; } if (ans<0) ans=-ans; if (ans) { if (ans<3) return puts("-1 -1"),0; for (lans=3;lans<ans&&ans%lans;++lans); return printf("%d %d",ans,lans),0; } if (sum<3) return puts("-1 -1"),0; return printf("%d 3",sum),0; }