参考:http://www.cnblogs.com/jackge/p/3231767.html 讲的很好
感悟:最好的情况肯定是完全图,但是不允许,所以一定是有些符合u->v,但是v不能到u,
在保证这样的情况,最大化边数,最终会形成两个图,然后应用不等式
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <string> #include <stack> #include <map> #include <queue> #include <algorithm> #include <utility> using namespace std; typedef long long LL; const int N=1e5+5; const int INF=0x3f3f3f3f; struct Edge{ int u,v,next; }edge[N]; int head[N],tot,n,m; void add(int u,int v){ edge[tot].u=u; edge[tot].v=v; edge[tot].next=head[u]; head[u]=tot++; } stack<int>s; bool instack[N]; int dfn[N],low[N],clk,cnt,bel[N],in[N],out[N],bcc[N]; void targin(int u){ dfn[u]=low[u]=++clk; instack[u]=true;s.push(u); for(int i=head[u];~i;i=edge[i].next){ int v=edge[i].v; if(!dfn[v]){ targin(v); low[u]=min(low[u],low[v]); } else if(instack[v]) low[u]=min(low[u],dfn[v]); } if(low[u]==dfn[u]){ ++cnt;int k; do{ k=s.top(); s.pop(); instack[k]=false; bel[k]=cnt;++bcc[cnt]; }while(k!=u); } } int main() { int T,cas=0; scanf("%d",&T); while(T--){ printf("Case %d: ",++cas); scanf("%d%d",&n,&m); for(int i=1;i<=n;++i){ head[i]=-1;dfn[i]=0;instack[i]=false; bcc[i]=0; } clk=cnt=tot=0; for(int i=1;i<=m;++i){ int u,v; scanf("%d%d",&u,&v); add(u,v); } for(int i=1;i<=n;++i) if(!dfn[i])targin(i); if(cnt==1){ printf("-1 ");continue; } for(int i=1;i<=cnt;++i)in[i]=out[i]=0; for(int i=0;i<tot;++i){ int u=bel[edge[i].u],v=bel[edge[i].v]; if(u==v)continue; ++out[u];++in[v]; } int ans=INF; for(int i=1;i<=cnt;++i) if(!in[i]||!out[i])ans=min(ans,bcc[i]); LL aim=1ll*n*(n-1)-1ll*ans*(n-ans)-m; printf("%I64d ",aim); } return 0; }