HDU 3639 Hawk-and-Chicken tarjan缩点+DFS
题意:
有n个人玩老鹰捉小鸡游戏,每个人都像当老鹰,于是他们决定投票选举,每个人都有一票,不可以投自己。票具有传递性假设A投给了B,B有又给了C则C就会得到两票。求得到票数最多的票数及每个人的编号(0-n-1)
思路:
其实划一划图就会发现,每个人得到的票数即为能够到达该点点数,中间可能存在环。如果五环的话,我们只要倒着建图,然后找出入度为0的点,搜索他能到达的点的个数即为该点所得到的票数,因为最优值一定在入度为0的点上。 如果存在环的话,我们只需要通过tarjan缩点,改环所能提供的票数为该环内的点数。然后再重新倒着建图就好了。
View Code
#include <iostream> #include <cstdio> #include <cmath> #include <vector> #include <cstring> #include <algorithm> #include <string> #include <set> #include <functional> #include <numeric> #include <sstream> #include <stack> #include <map> #include <queue> #define CL(arr, val) memset(arr, val, sizeof(arr)) #define lc l,m,rt<<1 #define rc m + 1,r,rt<<1|1 #define pi acos(-1.0) #define ll __int64 #define L(x) (x) << 1 #define R(x) (x) << 1 | 1 #define MID(l, r) (l + r) >> 1 #define Min(x, y) (x) < (y) ? (x) : (y) #define Max(x, y) (x) < (y) ? (y) : (x) #define E(x) (1 << (x)) #define iabs(x) (x) < 0 ? -(x) : (x) #define OUT(x) printf("%I64d\n", x) #define lowbit(x) (x)&(-x) #define Read() freopen("din.txt", "r", stdin) #define Write() freopen("dout.txt", "w", stdout); #define M 30007 #define N 5007 using namespace std; const int inf = 100000007; const int mod = 1000000007; struct node { int u,v; int next; }g1[M],g2[M]; int head1[N],head2[N]; int ct1,ct2; int low[N],dfn[N]; int belong[N]; int idx,top,cnt; bool isn[N]; int vt[N],no[N]; int stk[N]; int val[N]; int ind[N]; int n,m; void add1(int u,int v) { g1[ct1].v = v; g1[ct1].next = head1[u]; head1[u] = ct1++; } void add2(int u,int v) { g2[ct2].v = v; g2[ct2].next = head2[u]; head2[u] = ct2++; } void tarjan(int u) { low[u] = dfn[u] = ++idx; isn[u] = true; stk[++top] = u; for (int i = head1[u]; i != -1; i = g1[i].next) { int v = g1[i].v; if (!dfn[v]) { tarjan(v); low[u] = min(low[u],low[v]); } else if (isn[v]) { low[u] = min(low[u],dfn[v]); } } int j; if (low[u] == dfn[u]) { cnt++; do { j = stk[top--]; isn[j] = false; belong[j] = cnt; }while (j != u); } } void dfs(int u,int mk) { for (int i = head2[u]; i != -1; i = g2[i].next) { int v = g2[i].v; if (vt[v] != mk) { no[mk] += val[v]; vt[v] = mk; dfs(v,mk); } } } int main() { // Read(); int i,j,T; int cas = 1; scanf("%d",&T); while (T--) { scanf("%d%d",&n,&m); CL(head1,-1); ct1 = 0; int x,y; for (i = 0; i < m; ++i) { scanf("%d%d",&x,&y); x++; y++; add1(x,y); } CL(dfn,0); CL(low,0); CL(isn,false); idx = top = cnt = 0; for (i = 1; i <= n; ++i) { if (!dfn[i]) { tarjan(i); } } CL(val,0); for (i = 1; i <= n;++i) val[belong[i]]++; CL(head2,-1); ct2 = 0; CL(ind,0); for (i = 1; i <= n; ++i) { for (j = head1[i]; j != -1; j = g1[j].next) { int v = g1[j].v; if (belong[v] != belong[i]) { add2(belong[v],belong[i]); ind[belong[i]]++; } } } CL(no,0); int ans = 0; for (i = 1; i <= cnt; ++i) { CL(vt,0); if (ind[i] == 0) { no[i] = val[i] - 1; vt[i] = i; dfs(i,i); ans = max(ans,no[i]); } } printf("Case %d: %d\n",cas++,ans); bool flag = false; for (i = 1; i <= n; ++i) { if (no[belong[i]] == ans) { if (!flag) flag = true; else printf(" "); printf("%d",i - 1); } } printf("\n"); } return 0; }