题意:有一群孩子正在玩老鹰抓小鸡,由于想当老鹰的人不少,孩子们通过投票的方式产生,但是投票有这么一条规则:投票具有传递性,A支持B,B支持C,那么C获得2票(A.B共两票),然后问你获得最多票数的人是谁,最多能获得的票数是多少张
思路:原始思路是对每个点跑一次DFS,然后统计,但是由于case比较多,必然超时,所以我们得优化一下,这个题目可以转化为有X个点以自己为根,包含了I,输出最大的X以及相应的I,但是这样并不好想,我们通常的的由根至节点,这个题目是由节点至根,不好想,我们可以转化一下,转化为:以某个节点为根,最多拥有的儿子节点个数。但是这样还是会超时,不过我们可以考虑一下用强连通优化一下,强连通缩点之后跑DFS,但是如果每组数据都是链状的也会超时,我们注意一点,如果这个节点有入度的话,必然不是最优解(这个很好理解,自己想一下)
总结:对于有向图的题目,需要优化时,可以往强连通缩点方面想,比如这个题目,不缩点的话,每个点至少跑一次,缩点之后的效率大幅度提高。
code:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn = 7000;
struct edge
{
int u,v,next;
}e[maxn * 10];
int n,m,tot,cntnode,num,top,cnt;
int head[maxn],dfn[maxn],low[maxn],id[maxn],st[maxn],re[maxn];
int inc[maxn];
bool ins[maxn],vis[maxn],in[maxn];
void init();
void solve(int cas);
void tarjan(int u);
void add_edge(int u,int v);
void dfs(int f,int u);
int main()
{
int T,cas = 1;
scanf("%d",&T);
while(T --){
scanf("%d%d",&n,&m);
init();
for(int i = 0;i < m;i ++){
int u,v;
scanf("%d%d",&u,&v);
add_edge(v,u);
}
solve(cas ++);
}
return 0;
}
void init()
{
for(int i = 0;i < n;i ++){
ins[i] = in[i] = false;
head[i] = dfn[i] = low[i] = -1;
inc[i] = 0;
}
tot = top = cntnode = num = 0;
}
void add_edge(int u,int v)
{
e[tot].u = u , e[tot].v = v;
e[tot].next = head[u],head[u] = tot ++;
}
void tarjan(int u)
{
low[u] = dfn[u] = num ++;
ins[u] = true;
st[++ top] = u;
for(int i = head[u];i != -1;i = e[i].next){
int v = e[i].v;
if(dfn[v] == -1){
tarjan(v);
if(low[v] < low[u])
low[u] = low[v];
}
else if(ins[v] && dfn[v] < low[u])
low[u] = dfn[v];
}
if(low[u] == dfn[u]){
int v = -1;
while(u != v){
v = st[top --];
id[v] = cntnode;
ins[v] = false;
}
cntnode ++;
}
}
void solve(int cas)
{
for(int i = 0;i < n;i ++)
if(dfn[i] == -1) tarjan(i);
// for(int i = 0;i < n;i ++)
// printf("I:%d id:%d\n",i,id[i]);
for(int i = 0;i < n;i ++){
int idx = id[i];
inc[idx] ++;
}
memset(head,-1,sizeof(head));
for(int i = 0;i < m;i ++){
int u = id[e[i].u];
int v = id[e[i].v];
if(u != v)in[v] = true;
add_edge(u,v);
}
int ans = -1;
for(int i = 0;i < cntnode;i ++){
if(in[i]) continue;
cnt = 0;
for(int j = 0;j < cntnode;j ++) vis[j] = false;
dfs(i,i);
re[i] = cnt;
ans = max(ans,cnt);
}
vector<int> rec;
for(int i = 0;i < n;i ++){
int idx = id[i];
if(in[idx]) continue;
if(re[idx] == ans)
rec.push_back(i);
}
printf("Case %d: %d\n", cas ++,ans - 1);
for(int i = 0;i < rec.size();i ++)
printf("%d%c",rec[i],i == rec.size() - 1 ? '\n' : ' ');
}
void dfs(int f,int u)
{
cnt += inc[u];
if(vis[u]) return ;
vis[u] = true;
for(int i = head[u];i != -1;i = e[i].next){
int v = e[i].v;
if(v == f || v == u || vis[v]) continue;
dfs(u,v);
}
}