HDU 3639 Hawk-and-Chicken tarjan缩点+dfs

题意:投票,投票可以传递,当一个人投票时,要把此人的得票数全给被投的那个人,问最后按升序输出得票数最高的人。

想法:显然在一个连通块内的所有点的得票数都是一样的,即:块内点数-1,(1:是他自己本身)。所以先要tarjan缩点,然后求出每一个块可以由几个块到达(这里可以反向建边dfs)。最后输出最大得票数的人即可。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<stack>
#include<algorithm>
#define mm(x) memset(x,0,sizeof(x))
using namespace std;
const int N=5000+50;
const int M=30000+50;
int n,m;
int dfn[N],low[N],num[N],paint[N],instack[N],index,col;
int val[N],vis[N],res[N],ind[N];
struct node
{
	int v,next;
};
struct QXX
{
	int head[N],cnt;
	node e[M];
	void Init()
	{
		memset(head,-1,sizeof(head));
		cnt=0;
	}
	void add(int a,int b)
	{
		e[cnt].v=b;
		e[cnt].next=head[a];
		head[a]=cnt++;
	}
}qxx1,qxx2;
stack<int>s;
void tarjan_Init()
{
	index=col=0;
	mm(dfn);
	mm(low);
	mm(num);
	mm(paint);
	mm(instack);
	while(!s.empty()) s.pop();
}
int Min(int a,int b)
{
	if(a<b) return a;
	return b;
}
void tarjan(int u)
{
	dfn[u]=low[u]=++index;
	instack[u]=1;
	s.push(u);
	for(int i=qxx1.head[u];i+1;i=qxx1.e[i].next)
	{
		int v=qxx1.e[i].v;
		if(!dfn[v])
		{
			tarjan(v);
			low[u]=Min(low[u],low[v]);
		}
		else if(instack[v])
		{
			low[u]=Min(low[u],dfn[v]);
		}
	}
	if(low[u]==dfn[u])
	{
		++col;
		int k=s.top();
		while(u!=k)
		{
			s.pop();
			paint[k]=col;
			num[col]++;
			instack[k]=0;
			k=s.top();
		}
		s.pop();
		paint[u]=col;
		num[col]++;
		instack[u]=0;
	}
}
int dfs(int u,int &sum)
{
	vis[u]=1;
	sum+=num[u];
	for(int i=qxx2.head[u];i+1;i=qxx2.e[i].next)
	{
		int v=qxx2.e[i].v;
		if(vis[v]) continue;
		dfs(v,sum);
	}
}
int main()
{
	int t,ca=1;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d",&n,&m);
		tarjan_Init();
		qxx1.Init();
		for(int i=1;i<=m;i++)
		{
			int a,b;
			scanf("%d%d",&a,&b);
			qxx1.add(a,b);
		}
		for(int i=0;i<n;i++)
		{
			if(!dfn[i]) tarjan(i);
		}
		qxx2.Init();
		mm(ind);
		for(int i=0;i<n;i++)
		{
			int a=paint[i];
			for(int j=qxx1.head[i];j+1;j=qxx1.e[j].next)
			{
				int b=paint[qxx1.e[j].v];
				if(a!=b)
				{
					qxx2.add(b,a);
					ind[a]++;
				}
			}
		}
		mm(val);
		for(int i=1;i<=col;i++)
		{
			if(ind[i]==0)
			{
				mm(vis);
				int sum=0;
				dfs(i,sum);
				val[i]=sum;
			}
		}
		int maxx=-1;
		for(int i=1;i<=col;i++)
		{
			if(val[i]>maxx)
			{
				maxx=val[i];
			}
		}
		int num=0;
		for(int i=0;i<n;i++)
		{
			if(val[paint[i]]==maxx)
			{
				res[num++]=i;
			}
		}
		sort(res,res+num);
		printf("Case %d: %d\n",ca++,maxx-1);
		for(int i=0;i<num;i++)
		{
			if(i!=0) printf(" ");
			printf("%d",res[i]);
		}
		printf("\n");
	}
	return 0;
}
时间: 2024-08-28 07:58:10

HDU 3639 Hawk-and-Chicken tarjan缩点+dfs的相关文章

HDU 3836 Equivalent Sets(Tarjan+缩点)

Problem Description To prove two sets A and B are equivalent, we can first prove A is a subset of B, and then prove B is a subset of A, so finally we got that these two sets are equivalent. You are to prove N sets are equivalent, using the method abo

HDU 3639 Hawk-and-Chicken (强连通分量+树形DP)

题目地址:HDU 3639 先用强连通分量缩点,缩点之后,再重新按缩点之后的块逆序构图,每个块的值是里边缩的点的个数,那么得到选票的最大的一定是重新构图后入度为0的块,然后求出来找最大值即可. 代码如下: #include <iostream> #include <string.h> #include <math.h> #include <queue> #include <algorithm> #include <stdlib.h>

[tarjan] hdu 3639 Hawk-and-Chicken

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3639 Hawk-and-Chicken Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1986    Accepted Submission(s): 575 Problem Description Kids in kindergarte

(tarjan/+DFS+反向建图) hdu 3639

G - Hawk-and-Chicken Time Limit:2000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Practice HDU 3639 Description Kids in kindergarten enjoy playing a game called Hawk-and-Chicken. But there always exists a big problem: ev

hdu 3639 有向图缩点+建反向图+搜索

题意:给个有向图,每个人可以投票(可以投很多人,一次一票),但是一个人只能支持一人一次,支持可以传递,自己支持自己不算,被投支持最多的人. 开始想到缩点,然后搜索,问题是有一点想错了!以为支持按票数计算,而不是按人数!还各种树形dp/搜索求可以到达边数..提交WA了... 又反复读了题目之后才发现..错误..只要人数就行...问题简单了许多... 缩点成有向无环图后:每个SCC中支持的人数就是scc里面的人,要求可到达的点最多的点,当然要放过来求方便:反向图那个点可以到达的点最多!于是建反向图直

HDU 2767 Proving Equivalences(强连通 Tarjan+缩点)

HDU 2767 Proving Equivalences(强连通 Tarjan+缩点) ACM 题目地址:HDU 2767 题意: 给定一张有向图,问最少添加几条边使得有向图成为一个强连通图. 分析: Tarjan入门经典题,用tarjan缩点,然后就变成一个有向无环图(DAG)了. 我们要考虑的问题是让它变成强连通,让DAG变成强连通就是把尾和头连起来,也就是入度和出度为0的点. 统计DAG入度和出度,然后计算头尾,最大的那个就是所求. 代码: /* * Author: illuz <iil

hdu 4612 Warm up 双连通缩点+树的直径

首先双连通缩点建立新图(顺带求原图的总的桥数,其实由于原图是一个强连通图,所以桥就等于缩点后的边) 此时得到的图类似树结构,对于新图求一次直径,也就是最长链. 我们新建的边就一定是连接这条最长链的首尾,这样就将原图的桥减少了直径个. #include<iostream> #include<cstring> #include<cstdio> #include<vector> #include<algorithm> #include<map&g

POJ 1236 Network of Schools(强连通 Tarjan+缩点)

POJ 1236 Network of Schools(强连通 Tarjan+缩点) ACM 题目地址:POJ 1236 题意: 给定一张有向图,问最少选择几个点能遍历全图,以及最少加入?几条边使得有向图成为一个强连通图. 分析: 跟HDU 2767 Proving Equivalences(题解)一样的题目,只是多了个问题,事实上转化成DAG后就不难考虑了,事实上仅仅要选择入度为0的点即可了. 代码: /* * Author: illuz <iilluzen[at]gmail.com> *

HDU 3639 Hawk-and-Chicken(强连通)

HDU 3639 Hawk-and-Chicken 题目链接 题意:就是在一个有向图上,满足传递关系,比如a->b, b->c,那么c可以得到2的支持,问得到支持最大的是谁,并且输出这些人 思路:先强连通的缩点,然后逆向建图,对于每个出度为0的点,进行dfs求哪些点可达这个点 代码: #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #inclu