题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4635
题意:给你一个n个点m条边的图,问在图不是强连通图的情况下,最多可以向图中添多少条边,若图为原来就是强连通图,输出-1即可;
思路:最后得到的图肯定分为两部分x和y,且两部分均为强连通分量,要么x的点到y的所有点有边,要么,从y的所有点到x的所有点有边;(其中只有入度或出度为0的点才可能成为x或y)
则有 x+y=n
答案为 ans = y*(y-1) + x*(x-1)+ y*x - m;
化简后 ans = n*n - n -n*x - x*x - m;
由以上化简试,x越小,ans值越大(答案最多为一百亿,long long 之)
#include "stdio.h" //hdu 4635 强连通缩点 #include "string.h" #include "vector" #include "stack" using namespace std; #define N 201000 #define INF 0x3fffffff long long n,m; int time; stack<int> q; int dfn[N],low[N]; int MIN(int x,int y) { return x<y?x:y; } long long MAX(long long x,long long y) { return x>y?x:y; } struct node { int x,y; int next; }edge[2*N]; int idx,head[N]; bool vis[N]; void Init() { idx=0; memset(head,-1,sizeof(head)); } void Add(int x,int y) { edge[idx].x = x; edge[idx].y = y; edge[idx].next = head[x]; head[x] = idx++; } int countt; //统计缩点个数 int num[N]; //统计每个缩点内的点的个数 int ru_du[N],chu_du[N]; //统计缩点的出,入度 int belong[N]; //标记点属于哪个缩点 void DFS(int x) { int i,y; q.push(x); vis[x] = true; dfn[x] = low[x] = ++time; for(i=head[x]; i!=-1; i=edge[i].next) { y = edge[i].y; if(!dfn[y]) { DFS(y); low[x] = MIN(low[x],low[y]); } else if(vis[y]) //强双连通图出现的新判断条件 low[x] = MIN(dfn[y],low[x]); } if(low[x]==dfn[x]) { int temp; countt++; while(1) { temp = q.top(); q.pop(); belong[temp] = countt; num[countt]++; vis[temp] = false; //还原了~ if(temp==x) break; } } } long long Solve() { int i; int x,y; time = countt = 0; memset(dfn,0,sizeof(dfn)); memset(num,0,sizeof(num)); memset(belong,0,sizeof(belong)); memset(vis,false,sizeof(vis)); for(i=1; i<=n; ++i) { if(!dfn[i]) DFS(i); } if(countt==1) return -1; memset(ru_du,0,sizeof(ru_du)); memset(chu_du,0,sizeof(chu_du)); for(i=0; i<idx; ++i) { x = edge[i].x; y = edge[i].y; if(belong[x]!=belong[y]) { chu_du[belong[x]]++; ru_du[belong[y]]++; } } long long ans=0,mint; for(i=1; i<=countt; ++i) { if(chu_du[i]==0 || ru_du[i]==0){ mint = num[i]; ans = MAX(ans,n*n-n-mint*(n-mint)-m); } } return ans; } int main() { int T,Case=0; int i; int x,y; scanf("%d",&T); while(T--) { Init(); Case++; scanf("%lld %lld",&n,&m); for(i=0; i<m; ++i) { scanf("%d %d",&x,&y); Add(x,y); } printf("Case %d: ",Case); printf("%lld ",Solve()); } }