24h購物| | PChome| 登入
2013-05-29 16:12:45| 人氣1,828| 回應0 | 上一篇 | 下一篇

[UVA][SCC] 11324 - The Largest Clique

推薦 0 收藏 0 轉貼0 訂閱站台

Problem B: The Largest Clique

Given a directed graph G, consider the following transformation. First, create a new graph T(G) to have the same vertex set as G. Create a directed edge between two vertices u and v in T(G) if and only if there is a path between u and v in G that follows the directed edges only in the forward direction. This graph T(G) is often called the transitive closure of G.

We define a clique in a directed graph as a set of vertices U such that for any two vertices u and v in U, there is a directed edge either from u to v or from v to u (or both). The size of a clique is the number of vertices in the clique.

The number of cases is given on the first line of input. Each test case describes a graph G. It begins with a line of two integers n and m, where 0 ≤ n ≤ 1000 is the number of vertices of G and 0 ≤ m ≤ 50,000 is the number of directed edges of G. The vertices of G are numbered from 1 to n. The following m lines contain two distinct integers u and v between 1 and n which define a directed edge from u to v in G.

For each test case, output a single integer that is the size of the largest clique in T(G).

Sample input

1
5 5
1 2
2 3
3 1
4 1
5 2

Output for sample input

4

Zachary Friggstad

Clique 的定義跟我們平常想得不太一樣,
原本的定義是原本就有互相連通的關係子圖,在給定的隨意關係圖中尋找一個完全連接子圖。
原本是個 NP-hard 問題

好,這裡的 Clique 只的是一團內,有 semiconnected 即可,即任何兩點 u ~> v or v ~> u。

那麼將 SCC 縮點,然後會變成 DAG 圖,在其中找一條最長路徑即可,
在這裡最長路徑上面會有權重。

縮點之後,可以用拓樸排序在 O(V+E) 時間內進行 Dynamic programming 計算最長路徑,
又或者使用記憶化搜索計算之,下面使用記憶化搜索的方式進行。

#include <stdio.h>
#include <vector>
#include <queue>
#include <algorithm>
#include <string.h>
using namespace std;
vector<int> g[1005], dag[1005];
int vfind[1005], findIdx;
int stk[1005], stkIdx;
int in_stk[1005], visited[1005];
int contract[1005];
int scc(int nd) {
    in_stk[nd] = visited[nd] = 1;
    stk[++stkIdx] = nd;
    vfind[nd] = ++findIdx;
    int mn = vfind[nd];
    for(int i = 0; i < g[nd].size(); i++) {
        if(!visited[g[nd][i]])
            mn = min(mn, scc(g[nd][i]));
        if(in_stk[g[nd][i]])
            mn = min(mn, vfind[g[nd][i]]);
    }
    if(mn == vfind[nd]) {
        do {
            in_stk[stk[stkIdx]] = 0;
            contract[stk[stkIdx]] = nd;
        } while(stk[stkIdx--] != nd);
    }
    return mn;
}
int dp[1005], contSize[1005];
int dfs(int nd) {
    if(dp[nd])  return dp[nd];
    int ret = 0;
    for(int i = 0; i < dag[nd].size(); i++)
        ret = max(ret, dfs(dag[nd][i]));
    dp[nd] = ret + contSize[nd];
    return dp[nd];
}
int main() {
    int testcase, n, m;
    int x, y, i, j;
    scanf("%d", &testcase);
    while(testcase--) {
        scanf("%d %d", &n, &m);
        for(i = 1; i <= n; i++) {
            g[i].clear();
            dag[i].clear();
        }
        while(m--) {
            scanf("%d %d", &x, &y);
            g[x].push_back(y);
        }
        // SCC
        memset(visited, 0, sizeof(visited));
        memset(in_stk, 0, sizeof(in_stk));
        for(i = 1; i <= n; i++) {
            if(!visited[i]) {
                findIdx = stkIdx = 0;
                scc(i);
            }
        }
        memset(dp, 0, sizeof(dp));
        memset(contSize, 0, sizeof(contSize));
        for(i = 1; i <= n; i++) {
            x = contract[i];
            contSize[x]++;
            for(vector<int>::iterator it = g[i].begin();
                it != g[i].end(); it++) {
                y = contract[*it];
                if(x != y)
                    dag[x].push_back(y);
            }
        }
        // dp for a longest path
        int ret = 0;
        for(i = 1; i <= n; i++)
            ret = max(ret, dfs(contract[i]));
        printf("%d\n", ret);
    }
    return 0;
}

台長: Morris
人氣(1,828) | 回應(0)| 推薦 (0)| 收藏 (0)| 轉寄
全站分類: 不分類 | 個人分類: UVA |
此分類下一篇:[UVA][動態支配點] 11020 - Efficient Solutions
此分類上一篇:[UVA] 12150 - Pole Position

是 (若未登入"個人新聞台帳號"則看不到回覆唷!)
* 請輸入識別碼:
請輸入圖片中算式的結果(可能為0) 
(有*為必填)
TOP
詳全文