【HDU - 5917】Instability(规律,结论,Ramsey定理,知识点,tricks)
作者:互联网
题干:
Long long ago, there was a prosperous kingdom which consisted of n cities and every two cites were connected by an undirected road.
However, one day a big monster attacked the kingdom and some roads were destroyed. In order to evaluate the influence brought by the catastrophe, the king wanted to know the instability of his kingdom. Instability is defined as the number of the unstable subset of {1, 2,⋯⋯,n}.
A set S is unstable if and only if there exists a set A such that A⊆S(|A|≥3A⊆S(|A|≥3) and A is a clique or an independent set, namely that cites in A are pairwise connected directly or they are pairwise disconnected.
Archaeologist has already restored themroads that were not destroyed by the monster. And they want you to figure out the instability.
Since the answer may be tremendously huge, you are only required to write a program that prints the answer modulo 1000000007.
Input
The first line contains only one integer T, which indicates the number of test cases.
For each test case, the first line contains two integers n (3≤n≤503≤n≤50) and m (1≤m≤n(n−1)/21≤m≤n(n−1)/2), indicating the number of cities and the number of roads.
Then the following are m lines, each of which contains two integers x and y, indicating there is a road between the city x and the city y.
It is guarenteed that there does not exist a road connecting the same city and there does not exist two same roads.
Output
For each test case, print a line “Case #x: y”, where x is the case number (starting from 1) and y is an integer indicating the instability modulo 1000000007.
Sample Input
2 4 3 1 2 2 3 1 3 3 0
Sample Output
Case #1: 2 Case #2: 1
Hint
• In the first example, {1,2,3} and {1,2,3,4} , containing the subset {1,2,3} which is connected directly, are considered unstable. • In the second example, {1,2,3} is considered unstable because they are not pairwise connected directly.
题目大意:
给你一个n个点m条边的无向图,问图中有多少个“unstable ”的集合?定义“unstable”的集合为这个集合里面存在一个子集(大小>=3)为团或者是独立集。(n<=50)
解题报告:
首先观察数据范围,,感觉点数比较多的集合肯定都是“unstable”的,然后凑一下发现点数为6的时候就肯定是“unstable”的了,所以点数大于6的肯定也都是,所以可以直接组合数算出来,然后小范围的情况直接暴力dfs。比赛的时候组合数竟然写挂了,我以为C(n,m)中n只有50,m只有5,所以可以直接(n!)/((m!)*(n-m)!),,但是忘记了你算n!的时候会炸。真的是醉了。
赛后看题解发现有个定理:
Ramsey定理: 世界上任意6个人中,总有3个人相互认识,或互相皆不认识。
证明如下:首先,把这6个人设为A、B、C、D、E、F六个点。由A点可以引出AB、AC、AD、AE、AF五条线段。设:如果两个人认识,则设这两个人组成的线段为红色;如果两个人不认识,则设这两个人组成的线段为蓝色。
由抽屉原理可知:这五条线段中至少有三条是同色的。不妨设AB、AC、AD为红色。若BC,CD,BD至少存在一条为红色,则至少存在三人相互认识,结论成立。若BC,CD,BD均为蓝色,则B,C,D相互不认识,结论成立。
AC代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define FF first
#define SS second
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
typedef pair<int,int> PII;
const int MAX = 50 + 5;
const ll mod = 1e9 + 7;
int n,m;
int ok[MAX][MAX];
vector<int> vv;
ll ans,tmp;
int j3() {
int up = vv.size();
for(int i = 0; i<up; i++) {
for(int j = i+1; j<up; j++) {
for(int k = j+1; k<up; k++) {
int x = vv[i],y = vv[j],z = vv[k];
if(ok[x][y]+ok[x][z]+ok[y][z] == 3 || ok[x][y]+ok[x][z]+ok[y][z] == 0) return 1;
}
}
}
return 0;
}
int j4() {
int up = vv.size();
for(int i = 0; i<up; i++) {
for(int j = i+1; j<up; j++) {
for(int k = j+1; k<up; k++) {
for(int l = k+1; l<up; l++) {
int x = vv[i],y = vv[j],z = vv[k],q = vv[l];
if(ok[x][y]+ok[x][z]+ok[x][q]+ok[y][z]+ok[y][q]+ok[z][q] == 6 || ok[x][y]+ok[x][z]+ok[x][q]+ok[y][z]+ok[y][q]+ok[z][q] == 0) return 1;
}
}
}
}
return 0;
}
int j5() {
int up = vv.size();
for(int i = 0; i<up; i++) {
for(int j = i+1; j<up; j++) {
for(int k = j+1; k<up; k++) {
for(int l = k+1; l<up; l++) {
for(int p = l+1; p<up; p++) {
int x = vv[i],y = vv[j],z = vv[k],q = vv[l],w = vv[p];
if(ok[w][x]+ok[w][y]+ok[w][z]+ok[w][q]+ok[x][y]+ok[x][z]+ok[x][q]+ok[y][z]+ok[y][q]+ok[z][q] == 10 || ok[w][x]+ok[w][y]+ok[w][z]+ok[w][q]+ok[x][y]+ok[x][z]+ok[x][q]+ok[y][z]+ok[y][q]+ok[z][q] == 0) return 1;
}
}
}
}
}
return 0;
}
void dfs(int cur,int stp,int all) {
if(stp == all) {
if(all == 3) tmp += j3();
if(all == 4) tmp += j3()||j4();
if(all == 5) tmp += j3()||j4()||j5();
return;
}
for(int i = cur; i<=n; i++) {
vv.pb(i);
dfs(i+1,stp+1,all);
vv.pop_back();
}
}
ll C(int n,int m) {
ll tmp1 = 1,tmp2=1,tmp3=1;
for(int i = n; i>=n-m+1; i--) tmp1 *= i;
for(int i = 1; i<=m; i++) tmp2 *= i;
return tmp1/tmp2;
}
int main()
{
int T,iCase=0;
cin>>T;
while(T--) {
scanf("%d%d",&n,&m);ans=1;
memset(ok,0,sizeof ok);
for(int u,v,i = 1; i<=m; i++) scanf("%d%d",&u,&v),ok[u][v]=ok[v][u]=1;
for(int i = 1; i<=n; i++) ans = ans*2%mod;
ans = (ans+2*mod-1-n-n*(n-1)/2)%mod;
for(int i = 3; i<=min(n,5); i++) {
tmp=0;//每次都清零
vv.clear();
dfs(1,0,i);
ans = (ans+10*mod+tmp - C(n,i))%mod;
}
printf("Case #%d: %lld\n",++iCase,ans%mod);
}
return 0 ;
}
总结:其实dfs的时候每次判断如果不符合的情况就ans--就不会出现组合数爆longlong这种情况了(虽然主要还是代码写挂了)。上面代码中的写法是先用一个tmp变量记录符合的情况,然后再先减去组合数的情况(先认为都不合法),再加上合法情况。
标签:知识点,HDU,int,there,number,Ramsey,unstable,include,define 来源: https://blog.csdn.net/qq_41289920/article/details/100804578