Gym 101138C Stickmen【枚举+排列组合】

11 篇文章 0 订阅
8 篇文章 0 订阅

Description

standard input/output
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, biai ≠ 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

Input
7 8
1 2
1 3
1 4
1 5
1 6
5 6
7 5
7 6
Output
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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值