1. 程式人生 > >最大團演算法(codeforces839E)

最大團演算法(codeforces839E)

題意理解玩,YY一下,就知道要把K平均分給最大團裡面的每個點,然後乘積和就是答案。

最大團就是有n個點的完全圖,完全圖就是n個點有n*(n-1)/2條邊的圖、有高效演算法求的。。

//最大獨立集:一個圖中最大的互相沒有邊相連的點集。
//結論:原圖的最大獨立集等於補圖的最大團
const int maxn=1010;
int best;
int num[maxn];
// int x[maxn];
int path[maxn];
int g[maxn][maxn], n;
bool dfs( int *adj, int total, int cnt ){ // total: 與u相連的頂點數量  , cnt表示當前團的數量
    int i, j, k;
    int t[maxn];
    if( total == 0 ){ // 當此團中最後一個點 沒有 比起序號大 的頂點相連時
        if( best < cnt ){  // 問題1:best為最大團中頂點的數量
            // for( i = 0; i < cnt; i++) path[i] = x[i];
            best = cnt; return true;
        }
        return false;
    }
    for( i = 0; i < total; i++){ // 列舉每一個與 u 相連的頂點 adj[i]
        if( cnt+(total-i) <= best ) return false; // 剪枝1, 若當前 頂點數量cnt 加上還能夠增加的最大數量 仍小於 best則 退出並返回false
        if( cnt+num[adj[i]] <= best ) return false; // 剪枝2, 若當前 頂點數量cnt 加上 包含adj[i]的最大團頂點數 仍小於 best則 退出並返回false
        // x[cnt] = adj[i];
        for( k = 0, j = i+1; j < total; j++ ) // 掃描 與u相連的頂點  中與 adj[u]相連的頂點 並存儲到 陣列 t[]中,數量為k
            if( g[ adj[i] ][ adj[j] ] )
                t[ k++ ] = adj[j];
                if( dfs( t, k, cnt+1 ) ) return true;
    } return false;
}
int MaximumClique(){
    int i, j, k;
    int adj[maxn];
    if( n <= 0 ) return 0;
    best = 0;
    for( i = n-1; i >= 0; i-- ){
        // x[0] = i;
        for( k = 0, j = i+1; j < n; j++ )// 遍歷 [i+1, n] 間頂點,
            if( g[i][j] ) adj[k++] = j;
        dfs( adj, k, 1 ); // *adj, total, cnt
        num[i] = best;   // 得出頂點 i, 出發構成最大團 中頂點數量
    }
    return best;
}
int main()
{
    int  k;
    cin >> n >> k;
    for(int i = 0; i < n; i++)
    for(int j = 0; j < n; j++)
    scanf("%d", &g[i][j]);
    int t = MaximumClique();
    double ans = 0.5 * k * k * (t - 1) / t;
    printf("%.8lf\n", ans);
    return 0;
}