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;}
阅读全文
0 0
- POJ 6184 【三元环 +分治】
- HDU 6184 求三元环
- hdu 6184 三元环数目
- POJ-1741-treeDP+分治
- poj 3714 Raid 分治
- POJ 1741 点分治
- 【poj 1741】点分治
- poj 2114 点分治
- POJ 1741 树分治
- POJ-1741 点分治
- POJ 1741 点分治
- POJ 2114 点分治
- POJ 1741 树分治
- POJ - 3714 分治
- POJ - 1987 树分治
- poj 1741 点分治
- poj 1741 点分治
- 三元环的个数
- 关于未来编程方式的随想
- ubuntu里装java8(亲测有效)
- 最长上升子序列 o(n*logn)算法
- 统计文件夹(包含子文件夹)中每种类型的文件及个数
- 脚本语句
- POJ 6184 【三元环 +分治】
- MySQL语句
- string和stringBuffer的区别
- STL中(queue)用法简单运用
- BeanUtils使用
- 别人的百度面试
- adb常用命令总结(持续更新)
- C++ 读取和解析逗号分隔数据
- Effective C++