[hdu 5917 Instability] Ramsey定理

[hdu 5917 Instability] ramsey定理

题目链接[hdu 5917 Instability]
题意描述:有 N 个顶点,M条边,从 N 个顶点中选出若干个点,设为点集S,满足 AS , 且 |A|3 ,且集合 A 是一个团,或者是一个独立集。求有多少个满足要求的点集S
解题思路
先解释一下, Ramsey定理。

在组合数学上,拉姆齐(Ramsey)定理,又称拉姆齐二染色定理,是要解决以下的问题:要找这样一个最小的数 n ,使得n个人中必定有 k 个人相识或 l 个人互不相识。那么 R(k,l)=n
Ramsey定理应用的一个通俗的例子【友谊定理:世界上任意6个人中,总有3个人相互认识,或互相皆不认识。即 R(3,3)=6
关于 R(3,3)=6 的证明:请参考维基百科-拉姆齐定理

显然,当顶点个数 6 的时候,显然是满足条件的。直接求 C6n+C7n++Cnn
对于顶点个数为 3,4,5 的情况,单独考虑。暴力计算一下,复杂度也就 O(N5)

#include <bits/stdc++.h>
using namespace std;

typedef __int64 LL;
typedef pair<int, int> PII;

const int MAXN = 50 + 5;
const LL MOD  = 1000000007;

int T, N, M, cas;
bool G[MAXN][MAXN];
LL ans, C[MAXN][MAXN];

void I() {
    for(int i = 0; i < MAXN; i++) C[i][0] = 1;
    for(int i = 1; i < MAXN; i++) {
        for(int j = 1; j <= i; j++) {
            C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % MOD;
        }
    }
}
bool check(int sz, int buf[]) {
    int sum = 0;
    for(int i = 0; i < sz; i++) {
        for(int j = i + 1; j < sz; j++) {
            for(int k = j + 1; k < sz; k++) {
                if(G[buf[i]][buf[j]] && G[buf[j]][buf[k]] && G[buf[i]][buf[k]]) return true;
                if(!G[buf[i]][buf[j]] && !G[buf[j]][buf[k]] && !G[buf[i]][buf[k]]) return true;
            }
        }
    }
    return false;
}
inline void F(const int& v) {
    ans += v;
    if(ans >= MOD) ans -= MOD;
}
void solve() {
    int a[5];
    for(a[0] = 1; a[0] <= N; a[0]++) {
        for(a[1] = a[0] + 1; a[1] <= N; a[1]++) {
            for(a[2] = a[1] + 1; a[2] <= N; a[2]++) {
                if(check(3, a)) F(1);
                for(a[3] = a[2] + 1; a[3] <= N; a[3]++) {
                    if(check(4, a)) F(1);
                    for(a[4] = a[3] + 1; a[4] <= N; a[4]++) {
                        if(check(5, a)) F(1);
                    }
                }
            }
        }
    }
}

int main() {
//    freopen("input.txt", "r", stdin);
    int u, v; I();
    scanf("%d", &T); cas = 0;
    while(T --) {
        scanf("%d %d", &N, &M);
        ans = 0;
        if(N >= 6) {
            for(int i = 6; i <= N; i++) {
                F(C[N][i]);
            }
        }
        memset(G, false, sizeof(G));
        for(int i = 1; i <= M; i++) {
            scanf("%d %d", &u, &v);
            G[u][v] = G[v][u] = true;
        }
        solve();
        printf("Case #%d: %I64d\n", ++ cas, ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值