J题:Counting Triangles
题目大意
有一个n(n
≤
\leq
≤ 8000)个点的完全无向图,每条边被染为黑色或白色。求三角形(a,b,c)(a < b < c)的个数,使得(a,b),(b,c),(a,c)三边均为同一种颜色。
为避免输入过大,采用随机数生成边。
输入时给出种子seed(seed<109)
随机数生成边的代码题中已给出,如下。
namespace GenHelper
{
unsigned z1,z2,z3,z4,b,u;
unsigned get()
{
b=((z1<<6)^z1)>>13;
z1=((z1&4294967294U)<<18)^b;
b=((z2<<2)^z2)>>27;
z2=((z2&4294967288U)<<2)^b;
b=((z3<<13)^z3)>>21;
z3=((z3&4294967280U)<<7)^b;
b=((z4<<3)^z4)>>12;
z4=((z4&4294967168U)<<13)^b;
return (z1^z2^z3^z4);
}
bool read() {
while (!u) u = get();
bool res = u & 1;
u >>= 1; return res;
}
void srand(int x)
{
z1=x;
z2=(~x)^0x233333333U;
z3=x^0x1234598766U;
z4=(~x)+51;
u = 0;
}
}
using namespace GenHelper;
bool edge[8005][8005];
int main() {
int n, seed;
cin >> n >> seed;
srand(seed);
for (int i = 0; i < n; i++)
for (int j = i + 1; j < n; j++)
edge[j][i] = edge[i][j] = read();
return 0;
}
其中edge[i][j]=1代表节点i与j 之间的边为黑色。
思路
要求三边颜色相同的三角形个数,则只需要求出对立情况,即三边中有一边与另外两边颜色不同。再用总三角形数量减去对立情况三角形数即可。
因为只有两种颜色,对立情况的三角形数可以用每个点白边数
×
\times
× 黑边数
÷
\div
÷ 2 计算。
代码实现
#include<bits/stdc++.h>
#define ll long long
namespace GenHelper
{
unsigned z1,z2,z3,z4,b,u;
unsigned get()
{
b=((z1<<6)^z1)>>13;
z1=((z1&4294967294U)<<18)^b;
b=((z2<<2)^z2)>>27;
z2=((z2&4294967288U)<<2)^b;
b=((z3<<13)^z3)>>21;
z3=((z3&4294967280U)<<7)^b;
b=((z4<<3)^z4)>>12;
z4=((z4&4294967168U)<<13)^b;
return (z1^z2^z3^z4);
}
bool read()
{
while (!u) u = get();
bool res = u & 1;
u >>= 1;
return res;
}
void srand(int x)
{
z1=x;
z2=(~x)^0x233333333U;
z3=x^0x1234598766U;
z4=(~x)+51;
u = 0;
}
}
using namespace GenHelper;
using namespace std;
bool edge[8005][8005];
int num_b[8005],num_w[8005];
int main()
{
int seed;
ll sum=0,n;
cin >> n >> seed;
srand(seed);
for (int i = 0; i < n; i++)
for (int j = i + 1; j < n; j++)
edge[j][i] = edge[i][j] = read();
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
if(i==j) continue;
if(edge[i][j]==1)
num_b[i]++;
else if(edge[i][j]==0)
num_w[i]++;
}
}
for(int i=0;i<n;i++)
sum+=num_b[i]*num_w[i];
sum/=2;
cout<<n*(n-1)*(n-2)/6-sum<<"\n";
return 0;
}