UVA 1324 The Largest Clique 最大团(强连通分量,变形)

 

 

题意:给一个有向图,要求找出一些点,使得这些点中的任意点对,要么可以互通,要么单向可达。

思路:最低只要求单向可达即可,即a->b都可以算进去。

  强连通分量内的点肯定是满足要求的,可以全选,但是有多个强连通分量时就不行了,得有取舍。老方法,先缩点,缩完点后是没有环的存在的,所以就是拓扑图了。如果只给一个拓扑图,要求找一条链使得链上的点最多,那么可以用判断拓扑的方式,逐个将入度为0的点删除,且在删除的时候记录下最多有多少个点,删到最后一个点时就出结果了。这样的方法同样适用,只是每个点可能是缩点,而且要将这些缩点内的点数算上去而已。

实现:

  (1)求强连通分量。

  (2)统计缩点的度数并建(缩点)图。

  (3)按判断拓扑图的方式来进行点数的统计。

 

  1 #include <bits/stdc++.h>

  2 #define LL long long

  3 #define pii pair<int,int>

  4 using namespace std;

  5 const int N=1000+5;

  6 const int INF=0x7f7f7f7f;

  7 vector<int> vect[N], g[N];  //原图,缩点后的图

  8 int n, m;

  9 int dfn[N], lowlink[N], scc_no[N], dfn_clock, scc_cnt; //强连通分量必备

 10 stack<int> stac;    //强联通分量用栈

 11 unordered_map<int,int> chu[N],ru[N];    //仅仅为了防止重复统计

 12 int  r[N]; //出入度

 13 int num[N];     //强联通分量中的点数

 14 int dp[N];      //答案

 15 

 16 void DFS(int x)

 17 {

 18     stac.push(x);

 19     dfn[x]=lowlink[x]=++dfn_clock;

 20     for(int i=0; i<vect[x].size(); i++)

 21     {

 22         int t=vect[x][i];

 23         if(!dfn[t])

 24         {

 25             DFS(t);

 26             lowlink[x]=min(lowlink[x],lowlink[t]);

 27         }

 28         else if(!scc_no[t])    lowlink[x]=min(lowlink[x], dfn[t]);

 29     }

 30     if(lowlink[x]==dfn[x])

 31     {

 32         ++scc_cnt;

 33         while(true)

 34         {

 35             int t=stac.top();stac.pop();

 36             scc_no[t]=scc_cnt;

 37             if(t==x)    break;

 38         }

 39     }

 40 }

 41 

 42 

 43 int cal()

 44 {

 45     memset(dfn,0,sizeof(dfn));

 46     memset(lowlink,0,sizeof(lowlink));

 47     memset(scc_no,0,sizeof(scc_no));

 48     dfn_clock=scc_cnt=0;

 49     for(int i=1; i<=n; i++) if(!dfn[i]) DFS(i);

 50 

 51     if(scc_cnt==1)  return n;

 52     for(int i=1; i<=scc_cnt; i++)   g[i].clear(),chu[i].clear(),ru[i].clear();

 53     for(int i=1; i<=n; i++) //统计度,建图

 54     {

 55         for(int j=0; j<vect[i].size(); j++)

 56         {

 57             int t=vect[i][j];

 58             if(scc_no[i]!=scc_no[t])

 59             {

 60                 if(!chu[scc_no[i]][scc_no[t]])   //还没出现过

 61                 {

 62                     chu[scc_no[i]][scc_no[t]]=1;

 63                     g[scc_no[i]].push_back(scc_no[t]);

 64                 }

 65                 ru[scc_no[t]][scc_no[i]]=1;

 66             }

 67         }

 68     }

 69     deque<int> que;

 70     memset(r,0,sizeof(r));

 71     for(int i=1; i<=scc_cnt; i++)   //统计出入度

 72     {

 73         r[i]=ru[i].size();

 74         if(!r[i])   que.push_back(i);

 75     }

 76 

 77     memset(num,0,sizeof(num));

 78     for(int i=1; i<=n; i++)    num[scc_no[i]]++;    //统计点数

 79 

 80     memset(dp,0,sizeof(dp));    //按拓扑序来dp

 81     int ans=0;

 82     while(!que.empty())

 83     {

 84         int siz=que.size();

 85         for(int i=0; i<siz; i++)    //所有入度为0的节点

 86         {

 87             int t=que.front();que.pop_front();

 88             ans=max(ans,dp[t]+num[t]);

 89             for(int j=0; j<g[t].size(); j++)    //每条以t出发的边

 90             {

 91                 int d=g[t][j];

 92                 r[d]--;

 93                 if(!r[d])  que.push_back(d);

 94                 dp[d]=max(dp[d],dp[t]+num[t]);

 95             }

 96         }

 97     }

 98     return ans;

 99 }

100 

101 

102 int main()

103 {

104     //freopen("input.txt", "r", stdin);

105 

106     int t, a, b;

107     cin>>t;

108     while(t--)

109     {

110         scanf("%d%d", &n, &m);

111         for(int i=1; i<=n; i++) vect[i].clear();

112         for(int i=0; i<m; i++)

113         {

114             scanf("%d%d",&a,&b);

115             vect[a].push_back(b);

116         }

117         cout<<cal()<<endl;

118     }

119     return 0;

120 }
AC代码

 

你可能感兴趣的:(uva)