HDU 4635:Strongly connected(强连通入门)

来源:互联网 发布:解析域名 编辑:程序博客网 时间:2024/06/06 00:46

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4635



AC代码:

/*problem description:Give a simple directed graph with N nodes and M edges,a simple directed graph is defined as graph without duplicate edges and self loop.please program to calculate the maximum number of the edges you can add that the graph is still a simple directed graph. Also, after you add these edges, this graph must NOT be strongly connected. 翻译:给出一个N个点,M条边的有向图简单图,简单图被定义为没有重边和自环的图,现在请 你编程计算最多加多少边,可以使图仍然使简单图,且图不使强连通图。   解题思路:对于一个N个节点的有向强连通简单图来说,最多有N*(N-1)条边,由于图中已经存在 M条边,因此还剩余N*(N-1)-M条,我们就需要在剩余的这些边中删除一些边,使得图中边数最 多且图不是强连通。如果想要最大的不是强连通的图,我们就让图中有两个强连通分量就可以了, 因此我们就来缩点,并且要保存下来强连通分量里面的顶点的个数。我们要找到那些出度或入度 为0的新点(强连通分量构成的一点),设其内部点数为nodenum,我们要找到nodenum*(N-nodenum) 的最小值,然后用N*(N-1)-M减去这个最小值即可。 原因是除了这个点外,其他的连通分量任意两点之间都保证有边,而对于这个连通分量,它可能是 入度为0的点,或出度为0的点,如果是入度为0的点,则不能从其他强连通分量往这里个分量里面 引边,则损失的边数是nodenum*(N-nodenum).同样如果这个点是出度为0的点,则不允许在从当前 强连通分量往别的连通分量发出边,损失的是node*(N-nodenum),所以找出度或入度为0的顶点中 node*(N-nodenum)的最小值。*/#include <iostream>#include <stdio.h>#include <string.h>#define inf 9999900020using namespace std;const int maxn = 100010;const int maxm = 100010;long long N,M;int Stack[maxn];   ///栈int inStack[maxn]; ///标记节点是否在栈中int dfn[maxn];     ///访问节点的时间标记int low[maxn];     ///类似并查集合并数组int head[maxn];    ///类似链表头结点的数组long long num[maxn]; ///统计强连通分量中的节点个数int inDegree[maxn];  ///统计节点的入度int outDegree[maxn]; ///统计节点的出度int belong[maxn];    ///某个节点所书强连通分量的编号int edgeNumber,time,cnt,top; //四个变量分别是图边数,时间戳,强连通分量个数,栈顶指针//边节点struct Edge{    int u;    int v;    int nex;}edge[maxm];//加边函数void addEdge(int u,int v){    edge[edgeNumber].u = u;    edge[edgeNumber].v = v;    edge[edgeNumber].nex = head[u];    head[u] = edgeNumber++;}///强连通算法找强连通分量void tarjan(int u){    low[u] = dfn[u] = ++time;    Stack[++top] = u;    inStack[u] = 1;    for(int i = head[u]; i != -1; i = edge[i].nex)    {        int v = edge[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(dfn[u]==low[u])    {        cnt++;        int temp;        do        {            temp = Stack[top--];            num[cnt]++;            inStack[temp] = 0;            belong[temp] = cnt;        }while(temp != u);    }}///求解void solve(){    top = time = cnt = 0;    memset(num,0,sizeof(num));    memset(dfn,0,sizeof(dfn));    memset(low,0,sizeof(low));    for(int i = 1; i <= N; i++)    {        if(!dfn[i])        {            tarjan(i);        }    }}int main(){    int T,Case=0;    scanf("%d",&T);    while(T--)    {        scanf("%lld%lld",&N,&M);        memset(head,-1,sizeof(head));        edgeNumber = 0;        int u,v;        for(int i = 1; i <= M; i++)        {            scanf("%d%d",&u,&v);            addEdge(u,v);        }        solve();        if(cnt == 1) //图本身是强连通图        {            printf("Case %d: -1\n",++Case);        }        else        {            memset(inDegree,0,sizeof(inDegree));            memset(outDegree,0,sizeof(outDegree));            for(int i = 0; i < edgeNumber; i++)            {                u = edge[i].u;                v = edge[i].v;                u = belong[u];                v = belong[v];                if(u != v)                {                    outDegree[u]++;                    inDegree[v]++;                }            }            long long ans = N*(N-1)-M;            long long Min = inf;            for(int i = 1; i <= cnt; i++)            {                if(inDegree[i]==0 || outDegree[i]==0)                {                    Min = min(Min,num[i]*(N-num[i]));                }            }            printf("Case %d: %lld\n",++Case,ans-Min);        }    }    return 0;}



原创粉丝点击