给定一个有向图
求最多可以加多少条边 使加了边以后还是一个有向图而不是强联通图 由于不是一个强连通图,那么至少要有两个连通块。 也就是只有两个连通块时,加的边是最多的。 设有两个连通块 一个里有x个点,另一个里有个y个点 则第一个连通块中的路最多可以使x*(x-1) 第二个连通块中的路最多可以使y*(y-1) 两个连通块之间的路最多可以是(x*y) 那么一共可以连成x * (x-1)+y * (y-1)+x*y条边 又因为x+y=n 那么化简以后就是n*n-n-x*y 那么当x或y是0时 才有可能是答案 也就是找出入度或者出度是0的连通块 然后在减去一开始已经存在m条路 找出max(n*n+n-x*y-m)就是答案
#include#include #include using namespace std;const int maxn = 100005;const int maxm = 100005;int n, m;int top, tol, cnt;int stacksize;struct Node{ int u; int v; int next;};Node node[maxm];int dfn[maxn];int low[maxn];int vis[maxn];int num[maxn];int indi[maxn];int oudi[maxn];int head[maxn];int stack[maxn];int point[maxn];void init() { tol = top = stacksize = cnt = 0; memset(dfn, 0, sizeof(dfn)); memset(low, 0, sizeof(low)); memset(num, 0, sizeof(num)); memset(indi, 0, sizeof(indi)); memset(oudi, 0, sizeof(oudi)); memset(node, 0, sizeof(node)); memset(head, -1, sizeof(head)); memset(vis, false, sizeof(vis)); memset(point, 0, sizeof(point)); memset(stack, 0, sizeof(stack));}void addnode(int u, int v) { node[tol].u = u; node[tol].v = v; node[tol].next = head[u]; head[u] = tol++;}void dfs(int u) { int v; dfn[u] = low[u] = ++cnt; stack[stacksize++] = u; vis[u] = true; for(int i=head[u]; i!=-1; i=node[i].next) { v = node[i].v; if(!dfn[v]) { dfs(v); low[u] = min(low[u], low[v]); } else if(vis[v]) { low[u] = min(low[u], dfn[v]); } } if(low[u] == dfn[u]) { top++; do{ v = stack[--stacksize]; vis[v] = false; num[top]++; point[v] = top; } while(v != u); }}void tarjan() { for(int i=1; i<=n; i++) { if(!dfn[i]) { dfs(i); } }}int solve() { for(int u=1; u<=n; u++) { for(int i=head[u]; i+1; i=node[i].next) { int v = node[i].v; if(point[u] != point[v]) { oudi[point[u]]++; indi[point[v]]++; } } } int ans = 0; for(int i=1; i<=top; i++) { if(!oudi[i] || !indi[i]) { ans = max(ans, n*n-n-m-(n-num[i])*num[i]); } } return ans;}int main() { int T; scanf("%d", &T); int cas = 1; while(T--) { init(); scanf("%d%d", &n, &m); for(int i=0; i