您的位置:首页 > 其它

hdu 4635 Strongly connected(Tarjan)

2013-08-02 22:51 351 查看
做完后,看了解题报告,思路是一样的。我就直接粘过来吧

最终添加完边的图,肯定可以分成两个部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的点中,包含节点数最少的那个点,令它为一个部,其它所有点加起来做另一个部,就可以得到最多边数的图了

//109MS 	2916KB
#include <stdio.h>
#include <string.h>
#define LL long long
const int M = 100005;
const int inf = 0x3f3f3f3f;
struct Edge
{
int to,nxt;
} edge[M];

int head[M],low[M],dfn[M],stack[M+10];
int vis[M],out[M],in[M],belong[M];
int scc,cnt ,top,ep;
LL n,m;
int min (int a,int b)
{
return a > b ? b : a;
}
void addedge (int cu,int cv)
{
edge[ep].to = cv;
edge[ep].nxt = head[cu];
head[cu] = ep ++;
}

void Tarjan(int u)
{
int v;
dfn[u] = low[u] = ++cnt;
stack[top++] = u;
vis[u] = 1;
for (int i = head[u]; i != -1; i = edge[i].nxt)
{
v = edge[i].to;
if (!dfn[v])
{
Tarjan(v);
low[u] = min(low[u],low[v]);
}
else if (vis[v]) low[u] = min(low[u],dfn[v]);
}
if (dfn[u] == low[u])
{
++scc;
do
{
v = stack[--top];
vis[v] = 0;
belong[v] = scc;
}
while (u != v);
}
}

void solve()
{
int u,v;
scc = top = cnt = 0;
memset (vis,0,sizeof(vis));
memset (dfn,0,sizeof(dfn));
memset (out,0,sizeof(out));
memset (in,0,sizeof(in));
for (u = 1; u <= n; u ++)
if (!dfn[u])
Tarjan(u);

for (u = 1; u <= n; u ++)
{
for (int i = head[u]; i != -1; i =edge[i].nxt)
{
v = edge[i].to;
if (belong[u] != belong[v])
{
out[belong[u]] ++;
in[belong[v]] ++;
}
}
}
int num[M],Min;
memset (num,0,sizeof(num));
for (u = 1; u <= n; u ++)
if (!in[belong[u]]) num[belong[u]] ++;
for (u = 1; u <= scc; u ++)
if (num[u]!= 0&&num[u]<Min)
Min = num[u];

memset (num,0,sizeof(num));
for (u = 1; u <= n; u ++)
if (!out[belong[u]]) num[belong[u]] ++;
for (u = 1; u <= scc; u ++)
if (num[u]!= 0&&num[u]<Min)
Min = num[u];
if (scc == 1)
{
printf ("-1\n");
return ;
}
LL ans = n*(n-1)-Min*(n-Min) - m;
printf ("%I64d\n",ans);
}
int main ()
{
#ifdef LOCAL
freopen("in.txt","r",stdin);
#endif
int T,u,v,cnt = 0;
scanf ("%d",&T);
while (T --)
{
scanf ("%I64d%I64d",&n,&m);
ep = 0;
memset (head,-1,sizeof(head));
for (int i = 0; i < m; i++)
{
scanf ("%d%d",&u,&v);
addedge(u,v);
}
printf ("Case %d: ",++cnt);
solve();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: