hdu 3639 Hawk-and-Chicken 【强连通分量+反向建图dfs】

链接:http://acm.hdu.edu.cn/showproblem.php?pid=3639

题意:有n个人,m条边,每条边代表u给v投一票,票可以传递,比如A->B,B->C,这时C可以得到2票,求出得到最大票数的人有哪些。

分析:从一个强连通到另一个强连通分量的贡献为这两个强连通分量大小和减一。显然票数最大的人在图的端点。

将缩点后的图方向,可以得到一些入度为0的点,用DFS可以求出这些点的票数,最后去求出最大票数。

代码:

<pre name="code" class="cpp">#include <algorithm>
#include <iostream>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <vector>
#include <queue>
#include <cmath>
#include <stack>
#include <set>
#include <map>
#include <ctime>
#define INF 0x3f3f3f3f
#define Mn 10010
#define Mm 200010
#define mod 1000000007
#define CLR(a,b) memset((a),(b),sizeof((a)))
#define CPY(a,b) memcpy ((a), (b), sizeof((a)))
#pragma comment(linker, "/STACK:102400000,102400000")
#define ul (u<<1)
#define ur (u<<1)|1
using namespace std;
typedef long long ll;
struct edge {
    int v,next;
} e[Mm],e2[Mm];
int tot,head[Mm],tot2,head2[Mm];
void addedge(int u,int v) {
    e[tot].v=v;
    e[tot].next=head[u];
    head[u]=tot++;
}
void addedge2(int u,int v) {
    e2[tot2].v=v;
    e2[tot2].next=head2[u];
    head2[u]=tot2++;
}
int tarjan_clock=0,scc_cnt=0;
int pre[Mn],sccno[Mn],lowlink[Mn];
int Mnx[Mn],minn[Mn],value[Mn];
stack<int> sk;
void Tarjan(int u) {
    pre[u]=lowlink[u]=++tarjan_clock;
    sk.push(u);
    for(int i=head[u]; i!=-1; i=e[i].next) {
        int v=e[i].v;
        if(!pre[v]) {
            Tarjan(v);
            lowlink[u]=min(lowlink[u],lowlink[v]);
        } else if(!sccno[v])
            lowlink[u]=min(lowlink[u],pre[v]);
    }
    if(lowlink[u]==pre[u]) {
        scc_cnt++;
        while(1) {
            int x=sk.top();
            sk.pop();
            sccno[x]=scc_cnt;
            if(x==u)
                break;
        }
    }
}
void find_scc(int n) {
    tarjan_clock=scc_cnt=0;
    CLR(sccno,0);
    CLR(pre,0);
    for(int i=1; i<=n; i++) {
        if(!pre[i]) Tarjan(i);
    }
}
int vis[Mn];
int sum;
int sccnum[Mn];
void dfs(int u) {
    sum+=sccnum[u];
    vis[u]=1;
    for(int i=head2[u]; ~i; i=e2[i].next) {
        int v=e2[i].v;
        if(!vis[v]) dfs(v);
    }
}
void init() {
    tot=tot2=0;
    CLR(head,-1);
    CLR(head2,-1);
}
int in[Mn];
int ans[Mn];
int a[Mn];
int main() {
    int t;
    scanf("%d",&t);
    for(int cas=1; cas<=t; cas++) {
        init();
        int n,m;
        scanf("%d%d",&n,&m);
        while(m--) {
            int u,v;
            scanf("%d%d",&u,&v);
            u++,v++;
            addedge(u,v);
        }
        find_scc(n);
        CLR(in,0);
        CLR(sccnum,0);
        for(int u=1; u<=n; u++) {
            sccnum[sccno[u]]++;
            for(int i=head[u]; ~i; i=e[i].next) {
                int v=e[i].v;
                if(sccno[u]!=sccno[v]) {
                    in[sccno[u]]++;
                    addedge2(sccno[v],sccno[u]);
                }
            }
        }
        CLR(ans,0);
        int maxx=0;
        for(int i=1; i<=scc_cnt; i++) {
            if(in[i]==0) {
                CLR(vis,0);
                sum=0;
                dfs(i);
                ans[i]=sum;
                maxx=max(sum,maxx);
            }
        }
        int num=0;
        for(int i=1; i<=n; i++) {
            if(ans[sccno[i]]==maxx) {
                a[num++]=i-1;
            }
        }
        printf("Case %d: %d\n",cas,maxx-1);
        for(int i=0; i<num-1; i++) {
            printf("%d ",a[i]);
        }
        if(num)
            printf("%d\n",a[num-1]);
        else printf("\n");
    }
    return 0;
}
				
时间: 2024-11-05 20:42:44

hdu 3639 Hawk-and-Chicken 【强连通分量+反向建图dfs】的相关文章

【题解】SDOI2010所驼门王的宝藏(强连通分量+优化建图)

[题解]SDOI2010所驼门王的宝藏(强连通分量+优化建图) 最开始我想写线段树优化建图的说,数据结构学傻了233 虽然矩阵很大,但是没什么用,真正有用的是那些关键点 考虑关键点的类型: 横走型 竖走型 八连通型 本质上只有两种类型(走一大串/走八连通),我们考虑这样一种建图方法: 对于每一行每一列建立一个点(点权为\(0\)) 对于关键点建立一个点(点权为\(1\)) 然后考虑这样一种建图方式,得到一个有点权无边权图 关键点所在的行与列无偿地向这个关键点连边 横走型的关键点向行连一条边,竖走

HDU 3639 Hawk-and-Chicken(强连通缩点+反向建图)

http://acm.hdu.edu.cn/showproblem.php?pid=3639 题意: 有一群孩子正在玩老鹰抓小鸡,由于想当老鹰的人不少,孩子们通过投票的方式产生,但是投票有这么一条规则:投票具有传递性,A支持B,B支持C,那么C获得2票(A.B共两票),输出最多能获得的票数是多少张和获得最多票数的人是谁? 思路: 先强连通缩点反向建图,在计算强连通的时候,需要保存每个连通分支的结点个数. 为什么要反向建图呢?因为要寻找票数最多的,那么肯定是入度为0的点,然后dfs计算它的子节点的

HDU 3639 Hawk-and-Chicken(Tarjan缩点+反向DFS)

Problem Description Kids in kindergarten enjoy playing a game called Hawk-and-Chicken. But there always exists a big problem: every kid in this game want to play the role of Hawk. So the teacher came up with an idea: Vote. Every child have some nice

强连通 反向建图 hdu3639

Hawk-and-Chicken Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3321    Accepted Submission(s): 1041 Problem Description Kids in kindergarten enjoy playing a game called Hawk-and-Chicken. But t

hdu 1535 Invitation Cards(有向图的来回最短路,要反向建图)

题目: 链接:点击打开链接 题意: 给一个图,求1到各点和各点到1最短路. 思路: 先spfa,然后反向建图,在spfa就行了. 代码: #include <iostream> #include <cstdio> #include <queue> #include <cstring> using namespace std; #define INF 100000000 const int N = 1000010; struct node{ int u,v,w

HDU 2680 Choose the best route &lt;SPFA算法+反向建图&gt;

Choose the best route Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 10690    Accepted Submission(s): 3454 Problem Description One day , Kiki wants to visit one of her friends. As she is liabl

poj1122 FDNY to the Rescue!(dij+反向建图+输出路径)

题目链接:poj1122 FDNY to the Rescue! 题意:给出矩阵,矩阵中每个元素tij表示从第i个交叉路口到第j个交叉路口所需时间,若tij为-1则表示两交叉路口之间没有直接路径,再给出火警位置所在的交叉路口 和 一个或多个消防站所处的交叉路口位置.输出要求按消防站到火警位置所需时间从小到大排列,输出信息包括消防站位置(初始位置),火警位置(目标位置),所需时间,最短路径上每个交叉路口. 题解:反向建图,从火警位置求一次最短路,求最短路时记录路径,按时间从小到大输出. 1 #in

HDU2647(拓扑排序+反向建图)

题意不说了,说下思路. 给出的关系是a要求的工资要比b的工资多,由于尽可能的让老板少付钱,那么a的工资就是b的工资+1,可以确定关系为a>b,根据拓扑排序建边的原则是把"小于"关系看成有向边,那么我们可以建边v->u. #include <stdio.h> #include <string.h> #include <string> #include <iostream> #include <algorithm> #

HDU1535Invitation Cards(有向图,正向建图和反向建图各spfa一次)

Invitation Cards Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 2374    Accepted Submission(s): 1151 Problem Description In the age of television, not many people attend theater performances.