? (triangle)

2.1 题目描述

给定一个无自环重边的无向图,求这个图的三元环1的个数以及补图2的三元环个数。

2.2 输入格式

第一行 2 个数 n, m ,分别表示图的点数、边数。

接下来 m 行,每行两个数 u, v ,表示一条连接 u, v 的无向边。

2.3 输出格式

一行两个数,依次表示原图的三元环个数以及补图的三元环的个数。

2.4 样例输入

5 5

1 2

1 3

2 3

2 4

3 4

2.5样例输出

2 1

2.6数据范围

对于 30% 的数据:n ≤ 100

对于 60% 的数据:m ≤ 500

对于 100% 的数据:n ≤ 10^5 , m ≤ 10^5

2.7评分方式

如果你两个数均输出正确,得 10 分。

否则如果两个数中任意一个正确或者两个数的和正确,得 6 分。 否则不得分。

1大小为 3的环。即一个无序三元组 (x, y, z) 使得任意两点之间都有边

2一条连接(u, v)(u = v) 的边,如果在原图中出现了,那么在补图中不会出现,否则一定会在补图中出现。

题解

题目中说两个数的和正确可以得分,是不是说明先求和是一个突破口呐?

对于一个完全图,三元环的数量是C(n,3),少了一些边,就少了一些三元环,少的三元环应该有至少一条边在原图中,至少一条边在补图中。

减少的三元环数量为:sigma(d[i]*(n-1-d[i]))/2 (d[i]为度数)

一开始我想不通为什么是除以2,然后我画了两个图,就发现了答案,每个三元环可以被两个点找到。

剩下的就是求原图中的三元环,有一个神奇的算法,和分段暴力有一丢丢类似吧。

将所有点分成两类:d[i]<sqrt(m)的和d[i]>sqrt(m)的.

先求包含第一类点的三元环个数. 由于边很少,所以枚举2条边即可.由于一个点的度不超过sqrt(m),所以一条边最多被枚到(sqrt(m))次,最多枚M条边,所以这个操作时O(m*sqrt(m))的.

再求不包含第一类点的三元环个数. 由于每条边贡献2个度,所以二类点的数量是O(sqrt(m))级的.直接枚举三个点,复杂度O((sqrt(m))^3)=O(m*sqrt(m))

所以算法总的复杂度是O(m*sqrt(m))的.

我先用了一个vector来判断点i与j是否有边,但是T掉了,然后get到了一个聪明的把一条边的两个节点一起hash的方法,就写了一个hash表水过去了。

#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<set>
#define nn 100010
#define mod 1000007
#define base 2333
using namespace std;
namespace fastIO
{
#define buf_size 100000
    bool error;
    inline char gc()
    {
        static char buf[buf_size + 1],*l=buf,*r=buf;
        if(l==r)
        {
            l=buf;
            r=buf+fread(buf,1,buf_size,stdin);
            if(l==r) {error = 1;return -1;}
        }
       return *l++;
    }
    inline bool blank(char ch) {return ch==‘\n‘||ch ==‘\t‘||ch ==‘ ‘||ch ==‘\r‘||error;}
    inline bool getint(int &x)
    {
        char ch; int f = 1;
        while (blank(ch = gc())); if (error) return false;
        x = 0;
        if (ch == ‘-‘) f=-1,ch=gc();
        while (1){x = (x<<1) + (x<<3)+ch-‘0‘;if(!isdigit(ch = gc())) break;}
        x*=f;
        return true;
    }
    inline void putint(long long x)
    {
        if(!x) {putchar(‘0‘); return;}
        if(x<0){x=-x; putchar(‘-‘);}
        static int out[13];
        register int len = 0;
        while(x){out[++ len]=x%10; x/=10;}
        while(len) putchar(out[len --]+‘0‘);
    }
#undef buf_size
}
using namespace fastIO;
int in[nn],fir[nn],nxt[nn<<1],to[nn<<1],a[1000007],b[1000007],head[1000007],next[1000007];
bool hash[1000007];
int e=0,inum=0;
void add(int u,int v)
{
	nxt[++e]=fir[u];fir[u]=e;to[e]=v;
	nxt[++e]=fir[v];fir[v]=e;to[e]=u;
}
long long c(long long n,int m)
{
	long long an=(n-2)*(n-1)*n/6;
	return an;
}
void addd(int u,int v)
{
    int t=(u*base+v)%mod;
    a[++inum]=u;b[inum]=v;next[inum]=head[t];head[t]=inum;
  }
inline bool query(int u,int v)
{
    int t=(u*base+v)%mod;
    for (int p=head[t];p;p=next[p])
      if (a[p]==u&&b[p]==v)
    return 1;
    return 0;
  }
int main()
{
	freopen("triangle.in","r",stdin);
	freopen("triangle.out","w",stdout);
	int n,m,u,v;
	getint(n);getint(m);
	long long all=0,sum=0;
	for(register int i(1);i<=m;i++)
	{
		getint(u);getint(v);
		addd(u,v);
		add(u,v);
		in[u]++;in[v]++;
	}
	for(register int i(1);i<=n;i++)
	  all+=in[i]*(n-1-in[i]);
	all/=2;
	all=c(n,3)-all;
	for(register int i(1);i<=n;i++)
	{
		for(register int j=fir[i];j;j=nxt[j])
		  for(register int k=nxt[j];k;k=nxt[k])
		  {
		  	if(query(to[j],to[k])||query(to[k],to[j]))
		  	  sum++;
		  }
	}
	putint(sum/3);putchar(‘ ‘);putint(all-sum/3);
	return 0;
}
时间: 2024-10-01 07:08:57

? (triangle)的相关文章

(leetcode题解)Pascal&#39;s Triangle

Pascal's Triangle  Given numRows, generate the first numRows of Pascal's triangle. For example, given numRows = 5,Return [ [1], [1,1], [1,2,1], [1,3,3,1], [1,4,6,4,1] ] 题意实现一个杨辉三角. 这道题只要注意了边界条件应该很好实现出来,C++实现如下 vector<vector<int>> generate(int

Lab 1: Write a java program for the triangle problem and test the program with Junit.

Tasks: 1. Install Junit(4.12), Hamcrest(1.3) with Eclipse 将两个jar包添加到工程中 2. Install Eclemma with Eclipse 3. Write a java program for the triangle problem and test the program with Junit. [Description of triangle problem]Function triangle takes three i

Solution to Triangle by Codility

question: https://codility.com/programmers/lessons/4 we need two parts to prove our solution. on one hand, there is no false triangular. Given the array has been sorted, if A[i]+A[i+1]>A[i+2], we can prove the existence of the triangle. for array A i

LeetCode (13) Pascal&#39;s Triangle (杨辉三角 )

题目描述 Given numRows, generate the first numRows of Pascal's triangle. For example, given numRows = 5, Return 从第三行开始,每行除了最左边和最右边两个数为1,其他数字都是上一行中相邻两个数字之和.根据上述规则可以写出下面的代码: class Solution { public: vector<vector<int> > generateRow1() { vector<in

UVA - 11437 - Triangle Fun (计算几何~)

UVA - 11437 Triangle Fun Time Limit: 1000MS Memory Limit: Unknown 64bit IO Format: %lld & %llu Submit Status Description Problem A Triangle Fun Input: Standard Input Output: Standard Output In the picture below you can see a triangle ABC. Point D, E

POJ 1163 The Triangle

题目链接:http://poj.org/problem?id=1163 The Triangle Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 39022   Accepted: 23430 Description 7 3 8 8 1 0 2 7 4 4 4 5 2 6 5 (Figure 1) Figure 1 shows a number triangle. Write a program that calculat

LeetCode--Pascal&#39;s Triangle

Given numRows, generate the first numRows of Pascal's triangle. For example, given numRows = 5, Return [ [1], [1,1], [1,2,1], [1,3,3,1], [1,4,6,4,1] ] class Solution { public: vector<vector<int> > generate(int numRows) { vector<vector<in

POJ 2079 Triangle [旋转卡壳]

Triangle Time Limit: 3000MS   Memory Limit: 30000K Total Submissions: 9525   Accepted: 2845 Description Given n distinct points on a plane, your task is to find the triangle that have the maximum area, whose vertices are from the given points. Input

The Triangle

针对如下形式的ACM试题,大多出自南阳理工学院的在线ACM试题(网址: 南阳理工在线评测系统),在此非常感谢,同时也非常感谢作者的分享! 时间限制:1000 ms  |  内存限制:65535 KB 难度:4 描述 73 88 1 02 7 4 44 5 2 6 5(Figure 1)Figure 1 shows a number triangle. Write a program that calculates the highest sum of numbers passed on a ro