【新手向】最大團問題和最大獨立子集的懶人演算法(隨機化)
阿新 • • 發佈:2019-01-02
首先,團是什麼呢?
團就是一個點集,點集中任意兩點都有直接的邊相連
舉個栗子:
圖中紅色的點構成了一個團,當然單獨一個點也算是一個團。
那麼,獨立子集又是什麼呢?
和團正好相反,獨立子集也是一個點集,但是任意兩點之間都沒有直接的邊相連……
再舉個栗子……
圖中綠色的點構成了一個獨立子集,你說一個點是一個獨立子集我也沒意見……
那麼,最大團和最大獨立子集怎麼求呢?
首先最大獨立子集和最大團正好相反,所以最大獨立子集的數目就是這個圖的“補圖”的最大團……
(補圖就是一張圖有邊的改成沒邊,沒邊的改成有邊……)
於是最大獨立子集問題轉化成最大團問題
最大團又怎麼求呢???
最大團其實是個NP完全問題……目前常用的演算法是搜尋+優化和隨機化……
這裡介紹隨機化演算法(適合懶人……)
把點組成隨機組成一個排列,然後從前往後暴力找……首先第一個點可以組成一個最大團,然後加入第二個,看看是不是,如果是,加入第三個,如果不是,不加入第二個,直接加入第三個……這樣跑一邊是n^2的,但是答案並不一定正確,所以需要多次隨機,然後取max……
這樣的準確性還是挺高的,程式碼也不難打,這裡還是貼出來吧……(程式碼風格鬼畜,請做好心理準備!!!)
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <ctime>
using namespace std;
bool a[120][120];
int b[120];
bool p[120];
int n,m,x,y;
void RANDOM()
{
srand(time(0));
for(int i = 1;i <= n;i ++)
swap(b[i],b[rand()%n+1]);
return ;
}
int JUDGE()
{
for (int i = 1;i <= n;i ++)
p[i] = 0;
int ans = 0;
for(int i = 1;i <= n;i ++)
{
if(!p[i])
{
ans ++;
for(int j = i+1;j <= n;j ++)
{
if(!a[b[i]][b[j]])
p[j] = 1;
}
}
}
return ans;
}
int main()
{
cin >> n >> m;
for(int i = 1;i <= m;i ++)
{
cin >> x >> y;
a[x][y] = 1;
a[y][x] = 1;
}
for(int i = 1;i <= n;i ++)
b[i] = i;
int maxn = 0;
for(int i = 1;i <= 1000;i ++)
{
RANDOM();
maxn = max(maxn,JUDGE());
}
cout << maxn << endl;
return 0;
}