HDU 4635 Strongly connected(强连通分量,变形)

题意:给出一个有向图(不一定连通),问最多可添加多少条边而该图仍然没有强连通。

思路:

  强连通分量必须先求出,每个强连通分量包含有几个点也需要知道,每个点只会属于1个强连通分量。

  在使图不强连通的前提下,要添加尽可能多的边。边至多有n*(n-1)条,而已经给了m条,那么所能添加的边数不可能超过k=n*(n-1)-m。

  这k条边还有部分不能添加,一添加立刻就强连通。一个强连通图最少只需要n条边,根据强连通的特性,缩点之后必定是不会有环的存在的,那么只要继续保持没有环的存在即可。我们只要让其中1个强连通分量没有出度,或者没有入度就行了。到底选哪个强连通分量?选点数少的,这点在后面会了解。因为1*10=10,而2*9=18啊,也就是两个数越接近,两者之积越大。

  如果挑出1个出度(入度也行的,同理)为0的强连通分量,该强连通分量的点数为d,那么答案就是k-d*(n-d),即不允许有其他n-d个点有任何一条边指向此强连通分量,其他边都是可以存在的。那么要使得k-d*(n-d)最大,那么d*(n-d)要最小,就是上面讲的要选哪个强连通分量的原因。

  那么应该找到缩点后出/入度为0的且包含点数最少的强连通分量来计算即可。

 1 #include <bits/stdc++.h>
 2 #define LL long long
 3 #define pii pair<int,int>
 4 using namespace std;
 5 const int N=100000+5;
 6 const int INF=0x7f7f7f7f;
 7 vector<int> vect[N];
 8 stack<int> stac;
 9 int num[N], chu[N], ru[N];         //统计强连通分量中点的个数
10 int scc_no[N], lowlink[N], dfn[N], dfn_clock, scc_cnt;  //SCC必备
11 int n, m;
12 unordered_map<int,int>  mapp;
13 void DFS(int x) //常规tarjan
14 {
15     stac.push(x);
16     dfn[x]=lowlink[x]=++dfn_clock;
17     for(int i=0; i<vect[x].size(); i++)
18     {
19         int t=vect[x][i];
20         if(!dfn[t])
21         {
22             DFS(t);
23             lowlink[x]=min(lowlink[x],lowlink[t]);
24         }
25         else if(!scc_no[t]) //如果t不属于任何一个强连通分量
26             lowlink[x]=min(lowlink[x],dfn[t]);
27     }
28     if(lowlink[x]==dfn[x])
29     {
30         scc_cnt++;
31         while(true)
32         {
33             int t=stac.top();
34             stac.pop();
35             scc_no[t]=scc_cnt;
36             //scc[scc_cnt].push_back(t);
37             if(t==x)    break;
38         }
39     }
40 }
41
42
43 LL cal()
44 {
45     memset(dfn,0,sizeof(dfn));
46     memset(lowlink,0,sizeof(lowlink));
47     memset(scc_no,0,sizeof(scc_no));
48
49     dfn_clock=scc_cnt=0;
50     for(int i=1; i<=n; i++)    if(!dfn[i])    DFS(i);   //深搜
51     if(scc_cnt==1)  return -1;  //已经强连通
52
53     memset(chu,0,sizeof(chu));
54     memset(ru,0,sizeof(ru));
55     for(int i=1; i<=n; i++) //统计出入度数量
56         for(int j=0; j<vect[i].size(); j++)
57             if(scc_no[i]!=scc_no[vect[i][j]] )  chu[scc_no[i]]=ru[scc_no[vect[i][j]]]=true;
58
59     memset(num,0,sizeof(num));
60     for(int i=1; i<=n; i++)    num[scc_no[i]]++;    //统计每个scc中的点的数目
61     int small=INF;
62     for(int i=1; i<=scc_cnt; i++)    if(!chu[i]||!ru[i])   small=min(small,num[i]);//挑量小的,只要满足出/入度为0。如果都已经有出和入度了,那还计算啥!
63     return (LL)n*(n-1) - m - small*(n-small);   //注意10万*10万
64 }
65
66
67 int main()
68 {
69     freopen("input.txt", "r", stdin);
70     int a, b, t, j=0;
71     cin>>t;
72     while(t--)
73     {
74         scanf("%d%d",&n,&m);
75         mapp.clear();
76         int up=0;
77         for(int i=1; i<=n; i++) vect[i].clear();
78         for(int i=0; i<m; i++)
79         {
80             scanf("%d%d", &a, &b);
81             if(!mapp[a])    mapp[a]=++up;   //只是怕点号不连续,好像多余了
82             if(!mapp[b])    mapp[b]=++up;
83             vect[mapp[a]].push_back(mapp[b]);
84         }
85         printf("Case %d: %lld\n",++j,cal());
86     }
87     return 0;
88 }

AC代码

  

时间: 2024-10-11 12:19:30

HDU 4635 Strongly connected(强连通分量,变形)的相关文章

HDU 4635 Strongly connected 强连通分量

参考:http://www.cnblogs.com/jackge/p/3231767.html 讲的很好 感悟:最好的情况肯定是完全图,但是不允许,所以一定是有些符合u->v,但是v不能到u, 在保证这样的情况,最大化边数,最终会形成两个图,然后应用不等式 #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath>

HDU 4635 Strongly connected(强连通)经典

Strongly connected Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1828    Accepted Submission(s): 752 Problem Description Give a simple directed graph with N nodes and M edges. Please tell me

[tarjan] hdu 4635 Strongly connected

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4635 Strongly connected Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1568    Accepted Submission(s): 654 Problem Description Give a simple dir

HDU 4635 Strongly connected (有向图的强连通分量)

Strongly connected Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Problem Description Give a simple directed graph with N nodes and M edges. Please tell me the maximum number of the edges you can add that the grap

HDU 4635 —— Strongly connected——————【 强连通、最多加多少边仍不强连通】

Strongly connected Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Practice HDU 4635 Description Give a simple directed graph with N nodes and M edges. Please tell me the maximum number of the edges you can

hdu 4635 Strongly connected (tarjan)

题意:给一个n个顶点m条弧的简单有向图(无环无重边),求最多能够加入多少条弧使得加入后的有向图仍为简单有向图且不是一个强连通图.假设给的简单有向图本来就是强连通图,那么输出-1. 分析: 1.用tarjan算法求出强连通分量的个数,假设个数为1,那么输出-1,结束,否则运行2 2.如果将一些强连通分量合并为有n1个顶点简单全然图1,而将剩下的强连通分量合并为n2个顶点的简单全然图2,跨这两个简单全然图的弧的方向仅仅能是单向的,如果m1为全然图1内部的弧的数量,m2为为全然图2内部的弧的数量.m3

HDU 4635 Strongly connected(强连通分量缩点+数学思想)

题意:给出一个图,如果这个图一开始就不是强连通图,求出最多加多少条边使这个图还能保持非强连通图的性质. 思路:不难想到缩点转化为完全图,然后找把它变成非强连通图需要去掉多少条边,但是应该怎么处理呢……有人给出这样的答案,找到分量中点数最少的块,把它的所有入边都去掉……好像是对的,但是万一这个块本来就有一个入度怎么办?这个边是不可以删的啊.所以我觉得这种办法是有点的问题的,所以最靠谱的方法还是斌哥他们给出的方法,最后的时候把点分成两个集合x和y,x和y本身都是完全图块,然后让x中的每一个点都指向y

Hdu 4635 Strongly connected

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4635 1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 using namespace std; 6 7 typedef long long LL; 8 const int maxn = 100005; 9 const int INF

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

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