zoukankan      html  css  js  c++  java
  • HDU 4635

    t这道题在我们队属于我的范畴,最终因为最后一个环节想错了,也没搞出来

    题解是这么说的:

    最终添加完边的图,肯定可以分成两个部X和Y,其中只有X到Y的边没有Y到X的边,那么要使得边数尽可能的多,则X部肯定是一个完全图,Y部也是,同时X部中每个点到Y部的每个点都有一条边,假设X部有x个点,Y部有y个点,有x+y=n,同时边数F=x*y+x*(x-1)+y*(y-1),整理得:F=N*N-N-x*y,当x+y为定值时,二者越接近,x*y越大,所以要使得边数最多,那么X部和Y部的点数的个数差距就要越大,所以首先对于给定的有向图缩点,对于缩点后的每个点,如果它的出度或者入度为0,那么它才有可能成为X部或者Y部,所以只要求缩点之后的出度或者入度为0的点中,包含节点数最少的那个点,令它为一个部,其它所有点加起来做另一个部,就可以得到最多边数的图了

    而我只是考虑到了最大边数,于是就去求最小点的强连通分量,以下是错误例子:

    连通块A(10个点)->B(2个点)->C(10个点)

    B是最小的强连通分量,而它无法往A或C加边,所以必须求入度或出度为0的连通块

    #include <stdio.h>
    #include <string.h>
    #include <vector>
    #include <stack>
    #include <algorithm>
    using namespace std;
    #define LL long long
    const int maxn=100010;
    vector<int> G[maxn];
    int n,m;
    int pre[maxn],lowlink[maxn],sccno[maxn],dfs_clock,scc_cnt;
    int in[maxn],out[maxn];
    stack<int> S;
    
    void dfs(int u){
        pre[u]=lowlink[u]=++dfs_clock;
        S.push(u);
        for(int i=0;i<G[u].size();i++)
        {
            int v=G[u][i];
            if(!pre[v]){
                dfs(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++;
            for(;;){
                int x=S.top();S.pop();
                sccno[x]=scc_cnt;
                if(x==u)break;
            }
        }
    }
    
    void find_scc(int n){
        dfs_clock=scc_cnt=0;
        memset(sccno,0,sizeof(sccno));
        memset(pre,0,sizeof(pre));
        for(int i=0;i<n;i++)
            if(!pre[i])dfs(i);
    }
    
    int main()
    {
        LL ct[100010];
        int T,x,y,cas=0;
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d%d",&n,&m);
            for(int i=0;i<n;i++)
                G[i].clear();
            for(int i=0;i<m;i++)
            {
                scanf("%d%d",&x,&y);
                G[x-1].push_back(y-1);
            }
            find_scc(n);
            printf("Case %d: ",++cas);
            if(scc_cnt==1)
            {
                printf("-1
    ");
            }
            else
            {
                memset(ct,0,sizeof(ct));
                memset(in,0,sizeof(in));
                memset(out,0,sizeof(out));
                LL max=0;
                for(int i=0;i<n;i++)
                {
                    ct[sccno[i]]++;
                }
                for(int i=0;i<n;i++)
                {
                    for(int j=0;j<G[i].size();j++)
                    {
                        if(sccno[i]!=sccno[G[i][j]])
                        {
                        out[sccno[i]]++;
                        in[sccno[G[i][j]]]++;
                        }
                    }
                }
                for(int i=1;i<=scc_cnt;i++)
                {
                    if(in[i]==0||out[i]==0)
                    {
                       LL k=ct[i];
                       LL ans=k*(k-1)+(n-k)*(n-k-1)+k*(n-k)-m;
                       if(ans>max)max=ans;
                    }
                }
                printf("%I64d
    ",max);
            }
        }
        return 0;
    }
    


  • 相关阅读:
    ubuntu安装jdk的两种方法
    LeetCode 606. Construct String from Binary Tree (建立一个二叉树的string)
    LeetCode 617. Merge Two Binary Tree (合并两个二叉树)
    LeetCode 476. Number Complement (数的补数)
    LeetCode 575. Distribute Candies (发糖果)
    LeetCode 461. Hamming Distance (汉明距离)
    LeetCode 405. Convert a Number to Hexadecimal (把一个数转化为16进制)
    LeetCode 594. Longest Harmonious Subsequence (最长的协调子序列)
    LeetCode 371. Sum of Two Integers (两数之和)
    LeetCode 342. Power of Four (4的次方)
  • 原文地址:https://www.cnblogs.com/riskyer/p/3230718.html
Copyright © 2011-2022 走看看