POJ 6184 【三元环 +分治】

来源:互联网 发布:mac pro 无法关闭蓝牙 编辑:程序博客网 时间:2024/06/05 17:28

POJ6184入口

 题意: 给一张图,n(n<1e5),个点,m(m<2e5)条边,问能组成多少个,以同一条边构成的两个三元环。


思路:暴力枚举每一条边(两端点设为x,y)

 然后枚举第三个点z。

1.当du[y]<=sqrt(m),用lik记录所有与x相连的边。然后枚举与y相连的点z,判断z是否与x相连。算法时间m*(sqrt(m))。

2当du[y]>sqrt(m) ,枚举与x相连的点z,用二分在y中查找z(可以用set,耗时比二分多),每次查找时间log(g[y].size()).,由于这种点很少。每次时间与x相连的点数*log(与y相连的点数)

对于每条边枚举的三元环k,答案加上每个c(2,k)。

最终时间大概和m*log(m)。

分治。

(在POJ上提交 最优577ms,平均700ms,最差少于900ms)

ACcode

#include<cstring>#include<iostream>#include<cstdio>#include<algorithm>#include<vector>#include<set>#include<cmath>using namespace std;typedef long long LL;const int INF=0x3f3f3f3f;const int N=100005;vector<int> g[N];int n,m,du[N],lik[N];bool vis[N];LL ans,kk;int main(){    int x,y,z,B;    while(scanf("%d%d",&n,&m)!=EOF)    {        B=sqrt(m);        ans=0;        for(int i=1;i<=n;i++){g[i].clear();vis[i]=false;lik[i]=-1;du[i]=0;}        for(int i=1;i<=m;i++)        {            scanf("%d%d",&x,&y);            du[x]++;            du[y]++;            g[x].push_back(y);            g[y].push_back(x);        }        for(int i=1;i<=n;i++)sort(g[i].begin(),g[i].end());        for(int i=1;i<=n;i++)        {            x=i;            vis[x]=true;            for(int j=0;j<g[x].size();j++)             lik[g[x][j]]=x;            for(int j=0;j<g[x].size();j++)            {                kk=0;                y=g[x][j];                if(vis[y])continue;                if(du[y]<=B)                {                    for(int k=0;k<g[y].size();k++)                    {                        z=g[y][k];                        if(lik[z]==x)                            kk++;                    }                }                else                {                    for(int k=0;k<g[x].size();k++)                    {                         z=g[x][k];                        if(z!=x&&binary_search(g[y].begin(),g[y].end(),z))                            kk++;                     }                }                ans=ans+(kk-1)*kk/2;            }        }        printf("%lld\n",ans);    }    return 0;}



赛时代码改(800ms)

#include<cstring>#include<iostream>#include<cstdio>#include<algorithm>#include<vector>#include<cmath>using namespace std;typedef long long LL;const int INF=0x3f3f3f3f;const int N=100010;vector<int> g[N];int a[N*2],b[N*2],n,m,du[N],B;LL ans,k;int main(){    while(scanf("%d%d",&n,&m)!=EOF)    {        ans=0;        B=sqrt(m);        for(int i=1;i<=n;i++){g[i].clear();du[i]=0;}        for(int i=1;i<=m;i++)        {            scanf("%d%d",&a[i],&b[i]);            g[a[i]].push_back(b[i]);            g[b[i]].push_back(a[i]);            du[a[i]]++;            du[b[i]]++;        }        for(int i=1;i<=n;i++)        sort(g[i].begin(),g[i].end());        int x,y,xi,yi,z;        for(int i=1;i<=m;i++)        {            x=a[i];y=b[i];            xi=0;            yi=0;            k=0;            if(du[y]<=B&&du[x]<=B)            while(xi<g[x].size()&&yi<g[y].size())            {                if(g[x][xi]>g[y][yi])                    yi++;                else if(g[x][xi]<g[y][yi])                    xi++;                else                {//cout<<x<<" "<<y<<" "<<g[x][xi]<<endl;                    xi++;yi++;                    k++;                }            }            else if(du[x]<=B)            for(int j=0;j<g[x].size();j++)            {                z=g[x][j];                if(binary_search(g[y].begin(),g[y].end(),z))                    k++;            }            else            for(int j=0;j<g[y].size();j++)            {                z=g[y][j];                if(binary_search(g[x].begin(),g[x].end(),z))                    k++;            }            ans=ans+k*(k-1)/2;        }        printf("%lld\n",ans);    }    return 0;}