Suppose there are N people in ZJU, whose ages are unknown. We have some messages about them. The i-th message shows that the age of person si is not smaller than the age of person ti. Now we need to divide all these N people into several groups. One's age shouldn't be compared with each other in the same group, directly or indirectly. And everyone should be assigned to one and only one group. The task is to calculate the minimum number of groups that meet the requirement.
Input
There are multiple test cases. For each test case: The first line contains two integers N(1≤ N≤ 100000), M(1≤ M≤ 300000), N is the number of people, and M is is the number of messages. Then followed by M lines, each line contain two integers si and ti. There is a blank line between every two cases. Process to the end of input.
Output
For each the case, print the minimum number of groups that meet the requirement one line.
Sample Input
4 4 1 2 1 3 2 4 3 4
Sample Output
3
Hint
set1= {1}, set2= {2, 3}, set3= {4}
题意:有n个人,m个关系(a b),代表a会和b比较,且关系可以传递,问这么把这些人分到不同的群组里面,使得每个群组里面的人都不能比较,差不多是这个意思了。
第一感觉是强联通,得到一个有向无环图,找到最大的强联通分量,然后想想不太对,如果一个链够长,好像也可以,然后改了改,改成缩点之后,跑最长链,其中强联通分量的节点个数是该节点的权重,用个记忆话搜索,从重建的图中入度为0的点开始搜,找个最大值。
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
const int maxm = 300010;
const int maxn = 100010;
typedef struct Edge {
int to,next;
};
Edge edge[maxm];
int head[maxn],cnt;
int stack[maxn],instack[maxn],dfn[maxn],low[maxn],col[maxn];
int sec,top,ttime;
int ans_max,ans_len;
int deg[maxn],sum[maxn];
Edge redge[maxm];
int rhead[maxn],rcnt;
int mark[maxn];
int queue[maxn];
void Add(int from,int to) {
edge[cnt].to = to;
edge[cnt].next = head[from];
head[from] = cnt ++;
}
void rAdd(int from,int to) {
redge[rcnt].to = to;
redge[rcnt].next = rhead[from];
rhead[from] = rcnt ++;
}
void Tarjan(int s) {
stack[top ++] = s;
instack[s] = 1;
dfn[s] = low[s] = ttime ++;
for(int i = head[s]; i + 1; i = edge[i].next) {
int to = edge[i].to;
if(dfn[to] == -1) {
Tarjan(to);
low[s] = min(low[s],low[to]);
}
else if(instack[to]) {
low[s] = min(low[s],dfn[to]);
}
}
if(low[s] == dfn[s]) {
int x;
int t = 0;
do {
x = stack[-- top];
instack[x] = 0;
col[x] = sec;
t ++;
//printf("%d\n",x);
}while(s != x);
//printf("*****\n");
sum[sec] = t;
sec ++;
ans_max = max(ans_max,t);
}
}
void rebuild(int N) {
memset(rhead,-1,sizeof(rhead));
rcnt = 0;
for(int i = 1; i <= N; i ++) {
int from = i;
for(int j = head[i]; j + 1; j = edge[j].next) {
int to = edge[j].to;
if(col[from] != col[to]) {
rAdd(col[from],col[to]);
//printf("%d -> %d\n",col[from],col[to]);
}
}
}
}
int dfs(int s) {
int ans = 0;
//printf("s = %d\n",s);
for(int i = rhead[s]; i + 1; i = redge[i].next) {
int to = redge[i].to;
if(mark[to]) {
ans = max(ans,mark[to]);
continue;
}
dfs(to);
ans = max(ans,mark[to]);
}
mark[s] = ans + sum[s];
return mark[s];
}
int main() {
int N,M;
while(~scanf("%d%d",&N,&M)) {
memset(head,-1,sizeof(head));
memset(dfn,-1,sizeof(dfn));
memset(instack,0,sizeof(instack));
memset(sum,0,sizeof(sum));
top = cnt = sec = ttime = 0;
for(int i = 0; i < M; i ++) {
int a,b;
scanf("%d%d",&a,&b);
Add(a,b);
}
ans_max = 0;
for(int i = 1; i <= N; i ++) {
if(dfn[i] == -1) {
Tarjan(i);
}
}
//printf("ans_max = %d\n",ans_max);
//printf("sec = %d\n",sec);
rebuild(N);
memset(deg,0,sizeof(deg));
for(int i = 0; i < sec; i ++) {
for(int j = rhead[i]; j + 1; j = redge[j].next) {
int to = redge[j].to;
deg[to] ++;
}
}
ans_len = 0;
for(int i = 0; i < sec; i ++) {
if(deg[i] == 0) {
memset(mark,0,sizeof(mark));
int x = dfs(i);
ans_len = max(x,ans_len);
}
}
//printf("len = %d\n",ans_len);
printf("%d\n",max(ans_len,ans_max));
}
return 0;
}
做起来很舒服,没有什么难点,把简单的东西组合起来的题。