uva 11324(强连通分支+DAG)

题意:给一张有向图, 求一个结点数最大的结点集,使该节点集中任意两个结点u,v满足要么u可达v,要么v可达u。

思路:由于在无向图中的一个强连通分支内一旦一个点被选中那么这个分支内的其它点都会被选中,所以我们可以先求强连通分支然后缩点形成DAG。把强连通分支内点的个数看作是点的权值。再记忆化搜索就搞定了。

代码如下:

  1 /**************************************************
  2  * Author     : xiaohao Z
  3  * Blog     : http://www.cnblogs.com/shu-xiaohao/
  4  * Last modified : 2014-01-30 22:43
  5  * Filename     : uva_11324.cpp
  6  * Description     : 
  7  * ************************************************/
  8 
  9 #include <iostream>
 10 #include <cstdio>
 11 #include <cstring>
 12 #include <cstdlib>
 13 #include <cmath>
 14 #include <algorithm>
 15 #include <queue>
 16 #include <stack>
 17 #include <vector>
 18 #include <set>
 19 #include <map>
 20 #define MP(a, b) make_pair(a, b)
 21 #define PB(a) push_back(a)
 22 
 23 using namespace std;
 24 typedef long long ll;
 25 typedef pair<int, int> pii;
 26 typedef pair<unsigned int,unsigned int> puu;
 27 typedef pair<int, double> pid;
 28 typedef pair<ll, int> pli;
 29 typedef pair<int, ll> pil;
 30 
 31 const int INF = 0x3f3f3f3f;
 32 const double eps = 1E-6;
 33 const int LEN = 1010;
 34 vector<int> Map[LEN];
 35 int n, m, dclock, scc_cnt, dp[LEN];
 36 int  dfn[LEN], sccn[LEN], low[LEN], cnt[LEN], tMap[LEN][LEN];
 37 stack<int> s;
 38 
 39 void sccinit()
 40 {
 41      for(int i=0; i<LEN; i++) Map[i].clear();
 42      while(!s.empty()) s.pop();
 43      memset(dfn, 0, sizeof dfn);
 44      memset(sccn, 0, sizeof sccn);
 45      dclock = scc_cnt = 0;
 46 }
 47 
 48 void dfs(int u){
 49     low[u] = dfn[u] = ++dclock;
 50     s.push(u);
 51     for(int i=0; i<Map[u].size(); i++){
 52         int v = Map[u][i];
 53         if(!dfn[v]){
 54              dfs(v);
 55              low[u] = min(low[u], low[v]);
 56         }else if(!sccn[v]) low[u] = min(low[u], dfn[v]);
 57     }
 58     if(low[u] == dfn[u]){
 59          scc_cnt++;
 60          while(1){
 61             int x = s.top();s.pop();
 62             sccn[x] = scc_cnt;
 63             if(x == u) break;
 64          }
 65     }
 66 }
 67 
 68 int getans(int v){
 69     if(dp[v]!=-1) return dp[v];
 70     int ret = cnt[v];
 71     for(int i=1; i<=scc_cnt; i++) 
 72         if(tMap[v][i])ret = max(ret, cnt[v]+getans(i));
 73     return dp[v] = ret;
 74 }
 75 
 76 int main()
 77 {
 78 //    freopen("in.txt", "r", stdin);
 79     
 80     int a, b, T;
 81     scanf("%d", &T);
 82     while(T--){
 83         sccinit();
 84         scanf("%d%d", &n, &m);
 85         for(int i=0; i<m; i++){
 86             scanf("%d%d", &a, &b);
 87             Map[a].PB(b);
 88         }
 89         for(int i=1; i<=n; i++)if(!dfn[i])dfs(i);
 90         memset(cnt, 0, sizeof cnt);
 91         memset(tMap, 0, sizeof tMap);
 92         memset(dp, -1, sizeof dp);
 93         for(int i=1; i<=n; i++){
 94             for(int j=0; j<Map[i].size(); j++){
 95                 if(sccn[i] == sccn[Map[i][j]]) continue;
 96                 tMap[sccn[i]][sccn[Map[i][j]]] = 1;
 97             }
 98         }
 99         int ans = 0;
100         for(int i=1; i<=n; i++) cnt[sccn[i]] ++;
101         for(int i=scc_cnt; i>0; i--)if(dp[i] < 0)getans(i);
102         for(int i=scc_cnt; i>0; i--) ans = max(ans, dp[i]);
103         printf("%d\n", ans);
104     }
105     return 0;
106 }
View Code

 

转载于:https://www.cnblogs.com/shu-xiaohao/p/3536851.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值