題目連結
題目大意
給你一張完全圖,你可以刪除任意數量的邊
要求刪除完後剩餘的所有子圖必須是完全圖
問完全子圖數量最少是多少
解題思路
定義 \(ok[i]\) 表示狀態為 \(i\) 時所對應的點構成的圖是否為完全圖 (\(1\) 為是 , \(0\) 為否)
判斷完全圖可直接暴力列舉任意兩點檢查是否有邊
定義 \(dp[i]\) 表示狀態為 \(i\) 時所對應的點構成的所有子圖都為完全圖,且子圖數最小
其中 \(dp[0] = 0\)
那麼不難得到當 \(ok[j] = 1\) 時
\(dp[i] = min(dp[i] , dp[i\) ^\(j] + 1)\) , ( \(j\) 為 \(i\) 的子集 )
答案為 \(dp[1 << n - 1]\)
AC_Code
#include<bits/stdc++.h>
using namespace std;
const int N = 1LL << 19 , M = 20;
int n , m , dp[N] , ok[N] , g[M][M];
signed main()
{
cin >> n >> m;
for(int i = 1 ; i <= m ; i ++)
{
int x , y;
cin >> x >> y;
g[x][y] = g[y][x] = 1;
}
int sum = 1 << n;
for(int i = 0 ; i < sum ; i ++)
{
ok[i] = 1;
for(int j = 1 ; j <= n ; j ++) if(i >> (j - 1) & 1)
{
for(int k = j + 1 ; k <= n ; k ++) if(i >> (k - 1) & 1)
{
if(!g[j][k]) { ok[i] = 0 ; break ; }
}
if(!ok[i]) break ;
}
dp[i] = 1e9;
}
dp[0] = 0;
for(int i = 0 ; i < sum ; i ++)
{
for(int j = i ; j ; j = (j - 1) & i) if(ok[j])
{
dp[i] = min(dp[i] , dp[i ^ j] + 1);
}
}
cout << dp[sum - 1] << '\n';
return 0;
}