UVAlive11324 The Largest Clique(scc+dp)

题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=30726

【思路】

强连通分量+动归。

求scc后缩点,以scc中的节点数作为权值,则问题转化为求一个DAG上的最大权路径,可以用dp求解。

【代码】

 1 #include<cstdio>
 2 #include<stack>
 3 #include<vector>
 4 #include<cstring>
 5 #include<iostream>
 6 using namespace std;
 7
 8 const int maxn = 1000+10;
 9 const int maxm = 2000000+10;
10
11 int pre[maxn],lowlink[maxn],sccno[maxn],dfs_clock,scc_cnt;
12 vector<int> G[maxn];
13 stack<int> S;
14
15 int dfs(int u) {
16     pre[u]=lowlink[u]=++dfs_clock;
17     S.push(u);
18     for(int i=0;i<G[u].size();i++) {
19         int v=G[u][i];
20         if(!pre[v]) {
21             dfs(v);
22             lowlink[u]=min(lowlink[u],lowlink[v]);
23         }
24         else if(!sccno[v]) {
25             lowlink[u]=min(lowlink[u],pre[v]);
26         }
27     }
28     if(lowlink[u]==pre[u]) {
29         scc_cnt++;
30         for(;;) {
31             int x=S.top(); S.pop();
32             sccno[x]=scc_cnt;
33             if(x==u) break;
34         }
35     }
36 }
37 void find_scc(int n) {
38     memset(pre,0,sizeof(pre));
39     memset(sccno,0,sizeof(sccno));
40     scc_cnt=dfs_clock=0;
41     for(int i=0;i<n;i++)
42     if(!pre[i]) dfs(i);
43 }
44
45 int T,n,m;
46 int val[maxn];
47 struct Edge{  int u,v,next; } e[maxm];
48 int en,front[maxm];
49 void AddEdge(int u,int v) {
50     en++; e[en].u=u,e[en].v=v; e[en].next=front[u],front[u]=en;
51 }
52
53 int d[maxn];
54 int dp(int u) {
55     int& ans=d[u];
56     if(ans) return ans;
57     ans=0;
58     for(int i=front[u];i>=0;i=e[i].next) {
59         int v=e[i].v;
60         ans=max(ans,dp(v));
61      }
62     ans+=val[u];
63     return ans;
64 }
65 void init() {
66     en=-1;
67     memset(front,-1,sizeof(front));
68     memset(val,0,sizeof(val));
69     memset(d,0,sizeof(d));
70     for(int i=0;i<=n;i++) G[i].clear();
71 }
72 int main() {
73     scanf("%d",&T);
74     while(T--) {
75         scanf("%d%d",&n,&m);
76         init();
77         int u,v;
78         for(int i=0;i<m;i++) {
79             scanf("%d%d",&u,&v);
80             u--,v--;
81             G[u].push_back(v);
82         }
83         find_scc(n);
84         for(int i=0;i<n;i++) {
85             val[sccno[i]]++;
86             for(int j=0;j<G[i].size();j++) {
87                 int v=G[i][j];
88                 if(sccno[i]!=sccno[v]) AddEdge(sccno[i],sccno[v]);
89             }
90         }
91         int ans=0;
92         for(int i=1;i<=scc_cnt;i++)  ans=max(ans,dp(i));
93         printf("%d\n",ans);
94     }
95     return 0;
96 }

ps:实测该题vector数组式存边较自写邻接表快

时间: 2024-12-29 16:05:13

UVAlive11324 The Largest Clique(scc+dp)的相关文章

bzoj 1093 [ZJOI2007]最大半连通子图(scc+DP)

1093: [ZJOI2007]最大半连通子图 Time Limit: 30 Sec  Memory Limit: 162 MBSubmit: 2286  Solved: 897[Submit][Status][Discuss] Description Input 第一行包含两个整数N,M,X.N,M分别表示图G的点数与边数,X的意义如上文所述.接下来M行,每行两个正整数a, b,表示一条有向边(a, b).图中的每个点将编号为1,2,3…N,保证输入中同一个(a,b)不会出现两次. Outpu

hdu5593--ZYB&#39;s Tree(树形dp)

问题描述 ZYB有一颗N个节点的树,现在他希望你对于每一个点,求出离每个点距离不超过KK的点的个数. 两个点(x,y)在树上的距离定义为两个点树上最短路径经过的边数, 为了节约读入和输出的时间,我们采用如下方式进行读入输出: 读入:读入两个数A,B,令fai??为节点i的父亲,fa?1??=0;fa?i??=(A∗i+B)%(i−1)+1,i∈[2,N] . 输出:输出时只需输出N个点的答案的xor和即可. 输入描述 第一行一个整数TT表示数据组数. 接下来每组数据: 一行四个正整数N,K,A,

HDU 4960 (水dp)

Another OCD Patient Problem Description Xiaoji is an OCD (obsessive-compulsive disorder) patient. This morning, his children played with plasticene. They broke the plasticene into N pieces, and put them in a line. Each piece has a volume Vi. Since Xi

hdu 2089 不要62 (数位dp)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2089 思路:用变量记录吉利数,和最高位为2的吉利数还有不是吉利数的个数... code: #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int dp[10][3]; //dp[i][j] ,i表示位数,j表示状态<pre name="code"

hdu 3555 Bomb(数位dp)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3555 题目大意:就是给你一个数n,判断从0到n有多少个数含有数字49...... 是不是觉得跟hdu2089很相似呀... 思路:跟hdu2089一样的,注意给出的数比较大,所以这儿用__int64  .... code: #include<cstdio> #include<iostream> #include<cstring> #include<algorithm&

HDU4734——F(x)(数位DP)

dp[i][j]表示i位数权值不超过j的数的个数 注意点: dp[i][j]的值不用每次都初始化,因为它的值不受输入的影响,如果前面算过了就直接拿来用,没算过就拿来算并记录下来 <strong>#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<vector> #include<queue> #include&

poj2282(数位dp)

题意:计算a-b中各个数字出现的个数: 解法:数位dp(思想都是先算1-b的个数,然后减掉1-a中的个数),1-9数字的计算和前边计算1的那一篇数位dp差不多,计算0时候要加一维表示前缀是否全是0: 代码: /****************************************************** * author:xiefubao *******************************************************/ #pragma comment

POJ 2151 Check the difficulty of problems (概率dp)

题意:给出m.t.n,接着给出t行m列,表示第i个队伍解决第j题的概率. 现在让你求:每个队伍都至少解出1题,且解出题目最多的队伍至少要解出n道题的概率是多少? 思路:求补集. 即所有队伍都解出题目的概率,减去所有队伍解出的题数在1~n-1之间的概率 这里关键是如何求出某个队伍解出的题数在1~n-1之间的概率,采用dp的方法: 用p(i,j)表示前i道题能解出j道的概率,有p(i,j)=p(i-1,j)*(1-p(i))+p(i-1,j-1)*p(i)p(i)表示解出第i题的概率. #inclu

hdu 4081 Qin Shi Huang&#39;s National Road System(最小生成树+dp)

同样是看别人题解才明白的 题目大意—— 话说秦始皇统一六国之后,打算修路.他要用n-1条路,将n个城市连接起来,并且使这n-1条路的距离之和最短.最小生成树是不是?不对,还有呢.接着,一个自称徐福的游方道士突然出现,他说他可以不消耗任何人力财力,使用法术凭空造一条路,路的长度无所谓,但是只能造一条.那么问题来了,徐福希望将两座人口数最多的城市连接起来,而秦始皇希望将最长的路修好.最后折中了一下, 将A/B最大的一条路用法术修出来.其中A是两座城市的人口和,B是除了用法术修的路以外,其它需要修建的