ccpc 長春站 G - Instability(Ramsey定理)
阿新 • • 發佈:2020-11-03
題目連結:[http://acm.hdu.edu.cn/showproblem.php?pid=5917]
題意:
給你一個無向圖,問圖中有多少個符合條件的集合?條件為這個集合裡面存在一個子集(大小>=3),其中任意兩個點之間相連或者都是孤立點。答案mod 1e9+7。
思路:
- 先知道一個定理:Ramsey定理
該定理簡述為:6 個人中至少存在3人相互認識或者相互不認識。
該定理等價於證明這6個頂點的完全圖的邊,用紅、藍二色任意著色,必然至少存在一個紅色邊三角形,或藍色邊三角形
即:只要一個集合中有大於等於6個點,則一定符合條件
所以對集合大小大於6的部分直接求 - 小於6的部分暴力求解,n<=50,寫5重迴圈也是不會超時的
程式碼:
#include<cstdio> #include<cstring> #include<iostream> #include<sstream> #include<algorithm> #include<vector> #include<queue> #include<map> #include<cstdlib> #include<cmath> using namespace std; #define re register int #define ull unsigned long long #define ll long long #define INF 0x3f3f3f3f #define N 100010 #define lson rt<<1 #define rson rt<<1|1 #define mo 1000000007 #define lowbit(x) (x)&(-(x)) void FRE(){freopen("subsets.in","r",stdin);freopen("subsets.out","w",stdout);} inline ll read() { ll x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ll)(ch-'0');ch=getchar();} return x*f; } ll ans; int g[105][105],n,T,m; ll ksm(ll a,ll b) { ll tmp=1; while(b) { if (b&1) tmp=(tmp*a)%mo; b>>=1; a=(a*a)%mo; } return tmp; } ll niyuan(ll x) { return ksm(x,mo-2); } ll C(int n,int m) { ll tmp=1; for (ll i=1;i<=m;i++) { tmp=(tmp*(n-m+i)%mo)%mo; tmp=(tmp*niyuan(i)%mo)%mo; } return tmp; } bool OK(int i,int j,int k) { if (g[i][j]&&g[i][k]&&g[j][k]) return true; if (g[i][j]+g[i][k]+g[j][k]==0) return true; return false; } bool OK2(int i,int j,int k,int p) { if (OK(i,j,k)||OK(i,j,p)||OK(j,k,p)||OK(i,k,p)) return true; return false; } bool OK3(int i,int j,int k,int p,int pp) { if (OK2(i,j,k,p)||OK2(i,j,k,pp)||OK2(i,k,p,pp)||OK2(j,k,p,pp)||OK2(i,j,p,pp)) return true; return false; } int main() { T=read(); for (int tt=1;tt<=T;tt++) { memset(g,0,sizeof(g));ans=0; n=read(),m=read(); while (m--) { int x=read(),y=read(); g[x][y]=g[y][x]=1; } if (n>=6) { ans=ksm(2,n); for (int i=0;i<=5;i++) ans=(ans-C(n,i)+mo)%mo; } if (n>=3) { for (int i=1;i<=n;i++) for (int j=i+1;j<=n;j++) for (int k=j+1;k<=n;k++) if (OK(i,j,k)) ans=(ans+1)%mo; } if (n>=4) { for (int i=1;i<=n;i++) for (int j=i+1;j<=n;j++) for (int k=j+1;k<=n;k++) for (int p=k+1;p<=n;p++) if (OK2(i,j,k,p)) ans=(ans+1)%mo; } if (n>=5) { for (int i=1;i<=n;i++) for (int j=i+1;j<=n;j++) for (int k=j+1;k<=n;k++) for (int p=k+1;p<=n;p++) for (int pp=p+1;pp<=n;pp++) if (OK3(i,j,k,p,pp)) ans=(ans+1)%mo; } printf("Case #%d: %lld\n", tt, ans%mo); } return 0; }