传送门:点击打开链接
题目大意:
定义下图为“damn rhombus”,给定一个有向图,求出有多少个“damn
rhombus”。
解题思路1:
分析可以得出其实“damn rhombus”的意思就是求a->c通过2个节点中转的个数。也就是说 如果a->c中间中转了x个点,那么对于点对(a,c)来说“damn
rhombus”就有C(x,2)个。
那么通过层数为2的bfs就可以得出答案。
#include <iostream> #include <cstdio> #include <queue> #include <cstring> #include <algorithm> #define INF 0x7f7f7f7f #define maxn 3010 #define maxm 30010 using namespace std; struct Edge { int to; int next; }es[maxm]; int cnt,p[maxn]; int used[maxn]; int n,m; void add(int x,int y) { es[cnt].to = y; es[cnt].next = p[x]; p[x] = cnt++; } long long bfs(int x) { memset(used,0,sizeof used); queue <int > q; for(int i = p[x];i+1;i = es[i].next) q.push(es[i].to); while(!q.empty()) { int t = q.front(); q.pop(); for(int i = p[t];i+1;i = es[i].next) if(es[i].to != x) used[es[i].to]++; } long long res = 0; for(int i = 1;i <= n;i++) if(used[i] >= 2) res += (used[i]-1)*used[i]/2; return res; } int main() { scanf("%d %d",&n,&m); memset(p,-1,sizeof p); for(int i = 0;i < m;i++) { int x,y; scanf("%d %d",&x,&y); add(x,y); } long long ans = 0; for(int i = 1;i <= n;i++) { ans += bfs(i); } printf("%d\n",ans); return 0; }
解题思路2:
我在比赛的时候想到了一个很奇葩的做法。虽然被上面的代码skipped了。但是事实上是可以过的。悲伤的表情。
构造矩阵A。
A[i][j]表示从i->j不经过中转的路径数目。
那么学过线性代数的都知道,这个矩阵自乘的结果其实就是a[i][j]表示i->j经过一次中转的路径条数。只需要加一个优化就居然可以让O(n3)的代码过掉。
真的代码不要太短。
#include <iostream> #include <cstdio> #include <queue> #include <cstring> #include <algorithm> using namespace std; long long a[3010][3010]; long long res[3010][3010]; int n,m; int main() { scanf("%d %d",&n,&m); for(int i = 0;i < m;i++) { int x,y; scanf("%d %d",&x,&y); a[x][y]++; } for(int k = 1;k <= n;k++) for(int i = 1;i <= n;i++) { if(a[i][k] == 0) continue;//优化 for(int j = 1;j <= n;j++) res[i][j] += a[i][k]*a[k][j]; } long long ans = 0; for(int i = 1;i <= n;i++) for(int j = 1;j <= n;j++) { if(i == j) continue; ans += (res[i][j]*(res[i][j]-1))/2; } printf("%d\n",ans); return 0; }
时间: 2024-10-09 08:21:19