Description
Statements
Limak is a little bear who loves to play with graphs. Recently, he defined a new structure in a graph and called it a stickman.
A stickman is a set of 7 different vertices and 6 edges. Vertices should be connected by edges as in the image below.
You can see here two legs, two arms and a head. Formally, one vertex (the one between arms) must be connected to four other vertices and one of these four must be connected to two more vertices.
Limak has an undirected graph with n vertices and m edges, without loops and multiple edges. He asks you a favor. Could you count how many stickmen there are in Limak's graph, modulo 109 + 7?
A stickman is defined by a set of 7 vertices and 6 edges. Two stickmen are different if and only if the set of vertices isn't the same or the set of edges isn't the same. The order of vertices or edges doesn't matter (so you shouldn't distinguish legs for example).
Input
The first line of the input contains two integers n and m (7 ≤ n ≤ 200, ) — the number of vertices and the number of edges. Vertices are numbered 1 through n.
Each of the next m lines contains two integers ai and bi (1 ≤ ai, bi, ai ≠ bi) — indices of two vertices connected with an edge. Any unordered pair of vertices will appear at most once.
Output
Print the number of stickmen in the given graph, modulo 109 + 7.
Sample Input
7 8 1 2 1 3 1 4 1 5 1 6 5 6 7 5 7 6
2
Hint
There are two different stickmen in the sample, showed in the drawing below. Since there are only 7 vertices in the graph, the set of vertices of each stickman must contain all vertices. The two stickmen don't have the same set of edges though and this is why they are different at all.
/*
题意:告诉你火柴人的形状,给你一幅图,问你图中有多少个不同的火柴人
类型:枚举+组合数学
分析:枚举火柴人的躯干两个点,找上半部分(三个点)和下半部分(两个点)
有多少种组合C(num1,3)*C(num2,2)+C(num2,3)*C(num1,2)
注意去重,即上半部分和下半部分有重点,方法是,当上半部分和下半部分有重点
时,分别计算把重点给上半部分和把重点给下半部分
*/
#include <iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<set>
using namespace std;
int n,m;
typedef long long ll;
const int maxn=350;
const int maxm=maxn*maxn;
vector<int > G[maxn];
int du[maxn];
int a[maxm],b[maxm];
const ll mod=1000000007;
ll c[maxn][maxn];
void init(int n){
memset(c,0,sizeof(c));
for(int i=0;i<=n;i++){
c[i][0]=1;
for(int j=1;j<=i;j++){
c[i][j]=c[i-1][j-1]+c[i-1][j];
}
}
}
int main()
{
//freopen("D:\\12.txt","r",stdin);
init(320);
while(scanf("%d%d",&n,&m)!=EOF){
memset(du,0,sizeof(du));
for(int i=0;i<=n;i++){
G[i].clear();
}
for(int i=0;i<m;i++){
scanf("%d%d",&a[i],&b[i]);
du[a[i]]++;
du[b[i]]++;
G[a[i]].push_back(b[i]);
G[b[i]].push_back(a[i]);
}
ll sum=0;
int sz1,sz2,sz;
set<int> s;
for(int i=0;i<m;i++){
s.clear();
sz1=G[a[i]].size();
for(int j=0;j<sz1;j++){
s.insert(G[a[i]][j]);
}
sz2=G[b[i]].size();
for(int j=0;j<sz2;j++){
s.insert(G[b[i]][j]);
}
sz=sz1+sz2-s.size();
int p1=du[a[i]]-1-sz;
int p2=du[b[i]]-1-sz;
for(int j=0;j<=min(sz,3);j++){
if(p1+j>=3&&p2+sz-j>=2)
sum = (sum + c[sz][j]*c[p1][3-j]*c[p2+sz-j][2] )%mod;
}
for(int j=0;j<=min(sz,2);j++)
if(p1+j>=2&&p2+sz-j>=3)
sum = (sum + c[sz][j]*c[p1][2-j]*c[p2+sz-j][3] )%mod;
}
printf("%I64d\n",sum%mod);
}
return 0;
}