bzoj1064: [Noi2008]假面舞会

时间:2022-05-05 00:31:13

莫名其妙的dfs算法。

1.这道题首先要推出来,如果有弓形或者环形,答案必须是环长度和弓形俩条路长度之差的约数。

而且如果你直接按照原图来建图你是跑不出来的。

1.如果你每个点访问一次时dfs所有点,tle。

2.如果你打vis标记,你判断不出来弓形,wa。

3.如果妄图用一个in数组记录哪个点in[u]=0,然后从这个点开始跑的话。整体做个环,甩出去个头支的。wa+奇奇怪怪的错误。

所以我们要求每个点逆向也可以跑。

所以建图为 a->b 1,b->a->-1。

这样上述问题就不会出现了。

2.如果没有上述情况,肯定就是个dag图。跑dfs就行了。

然后求最多可能有多少类面具的答案为sum(最长链的长度)。用心去感受

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
const int maxn = 100000 + 10;
const int maxm = 4000000 + 10;
const int inf = 0x3f3f3f3f;
int g[maxn],v[maxm],next[maxm],dist[maxm],eid;
int c[maxn];
bool vis[maxn],inque[maxn],mark;
int n,m,ans,l,r,minres,maxres,u;
queue<int> q;

void addedge(int a,int b,int c) {
    v[eid]=b; dist[eid]=c; next[eid]=g[a]; g[a]=eid++;    
}

int gcd(int a,int b) {
    return b==0?a:gcd(b,a%b);    
}

void dfs(int u,int fa,int d) {
    if(vis[u]) {
        ans=gcd(ans,abs(d-c[u]));
        return;
    }
    vis[u]=1;
    c[u]=d;
    for(int i=g[u];~i;i=next[i]) if(v[i]!=fa) dfs(v[i],u,c[u]+dist[i]);
}

void build() {
    memset(g,-1,sizeof(g));
    scanf("%d%d",&n,&m);
    for(int i=1,a,b;i<=m;i++) {
        scanf("%d%d",&a,&b);
        addedge(a,b,1);
        addedge(b,a,-1);
    }
}

void spfa(int u) {
    inque[u]=1;
    l=min(l,c[u]);
    r=max(r,c[u]);
    for(int i=g[u];~i;i=next[i]) if(!inque[v[i]]) {
        c[v[i]]=c[u]+dist[i];
        spfa(v[i]);
    }
}

void solve() {
    for(int i=1;i<=n;i++) if(!vis[i]) dfs(i,0,0);
    if(ans&&ans<=2) {
        printf("-1 -1\n");
        return;    
    }
    if(ans) {
        maxres=ans;
        for(int i=3;i<=maxres;i++) if(maxres%i==0) {
            minres=i;
            break;
        }
    }
    else for(int i=1;i<=n;i++) if(!inque[i]) {
        l=r=c[i]=0;
        spfa(i);
        maxres+=r-l+1;
        minres=3;
    }
    if(maxres<3) maxres=minres=-1;
    printf("%d %d\n",maxres,minres);
}

int main() {
    build();
    solve();
    return 0;
}