JOISC2014 Day2 E "交朋友" (思维+假的SCC)

传送门

题目描述
你是活跃在历史幕后的一名特工,为了世界和平而夜以继日地努力着。
这个世界有N个国家,编号为1..N;
你的目的是在这N个国家之间建立尽可能多的友好关系。
你为了制定一个特工工作的计划,作出了一张当今国际关系的示意图。
你准备了一张非常大的画纸,先画下了代表每个国家的N个点。
接下来,为了表示现在的国际关系,画下了M个连接两个国家的有向边;
其中从国家u连向国家v的有向边,表示国家u向国家v派遣了大使,下文称作边(u,v)。
这样就做出了N个点M条边的当今国际关系示意图。

作为两国友好关系的开端,两国之间需要进行「友好条约缔结会议」,以下简称会议。
如果某两个国家p和q要进行会议,那么需要一个向两国都派遣了大使的国家x作为中介。
会议结束后,会议的双方相互向对方的国家派遣大使。
换句话说,为了让国家p和国家q进行会议,必须存在一个国家x满足边(x,p)和边(x,q)都存在;
并且在会议后添加两条边(p,q)和(q,p)(如果需要添加的某条边已经存在则不添加)。
你的工作是对于可以进行会议的两国,选择会议的中介并促使会议进行。
使用这张图进行工作的模拟的话,世界距离和平还有多远的一个重要的基准就是这张图上的边数。

现在给出国家的个数以及当今国际关系的情报,请你求出反复选择两个国家,促使它们进行会议后,图上最多会有多少条边。

输入
第一行两个空格分隔的整数N和M,分别表示世界上国家的个数和图中的边数。
接下来M行描述画纸上的有向边的信息,其中第i行有两个空格分隔的整数ai和bi,表示图中有一条从ai到bi的有向边。

输出
输出一行一个整数,表示能实现的边数的最大值。
注意这个边数包括原有的边数和新连接的边数。
题目描述
样例输入
5 4
1 2
1 3
4 3
4 5

样例输出
10

样例解释
国家1作为中介国,国家2与3开会。
国家4作为中介国,国家3与5开会。
国家3作为中介国,国家2与5开会。
样例输入输出

数据范围:1≤N≤105,1≤M≤2×105,1≤ai,bi≤N,ai≠bi,(ai,bi)≠(aj,bj)

参考资料:

  [1]:http://icpc.upc.edu.cn/blog/?p=108

题意(摘抄自[1]):

  如果存在有向边<a,b>和<a,c>,就添加两条有向边<b,c>和<c,b>(已经存在就不添加),问最多有多少条边;

题解:

  昨天比赛做这道题的时候,想到了SCC,但我真的用SCC了,中间过程处理的不好(代码写搓了,逃)........

扫描二维码关注公众号,回复: 6303988 查看本文章

  今天晚上补这道题,看了看题解,和昨天自己想的差不多,就是代码实现上,[1]并没有用SCC知识用SCC思考这道题的做法;

  哎,欠缺的还是太多了,理解了将近半个小时,终于理解了,tql;

  下面谈谈我的进一步理解:

  (看会专业课先,理解明天写,下周要考两门,orz)

AC代码(偷偷换成了我的风格):

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define ll long long
  4 #define mem(a,b) memset(a,b,sizeof(a))
  5 const int maxn=1e5+50;
  6 
  7 int n,m;
  8 int num;
  9 int head[maxn];
 10 struct Edge
 11 {
 12     int to;
 13     int next;
 14 }G[maxn<<1];
 15 void addEdge(int u,int v)
 16 {
 17     G[num]={v,head[u]};
 18     head[u]=num++;
 19 }
 20 ll tot[maxn];
 21 int fa[maxn];
 22 int Find(int x)
 23 {
 24     return fa[x] == -1 ? x:fa[x]=Find(fa[x]);
 25 }
 26 void DFS(int u,int x)
 27 {
 28     for(int i=head[u];~i;i=G[i].next)
 29     {
 30         int y=G[i].to;
 31         x=Find(x);
 32         y=Find(y);
 33 
 34         if(x == y)
 35             continue;
 36 
 37         fa[y]=x;
 38         tot[x] += tot[y];
 39         DFS(y,x);
 40     }
 41 }
 42 ll Solve()
 43 {
 44     bool update=true;
 45     while(update)
 46     {
 47         update=false;
 48         for(int u=1;u <= n;++u)
 49         {
 50             int x=tot[Find(u)] == 1 ? -1:u;
 51             for(int i=head[u];~i;i=G[i].next)
 52             {
 53                 int y=G[i].to;
 54                 if(x == -1)
 55                     x=y;
 56                 else
 57                 {
 58                     x=Find(x);
 59                     y=Find(y);
 60                     if(x == y)
 61                         continue;
 62                     fa[y]=x;
 63                     tot[x] += tot[y];
 64                     DFS(y,x);
 65                     update=true;
 66                 }
 67             }
 68         }
 69     }
 70     ll ans=0;
 71     for(int u=1;u <= n;++u)
 72     {
 73         if(fa[u] != -1)
 74             continue;
 75 
 76         ans += tot[u]*(tot[u]-1);
 77         for(int i=head[u];~i;i=G[i].next)
 78         {
 79             int x=Find(u);
 80             int y=Find(G[i].to);
 81 
 82             if(x != y)
 83                 ans++;
 84         }
 85     }
 86     return ans;
 87 }
 88 void Init()
 89 {
 90     num=0;
 91     for(int i=0;i <= n;++i)
 92         head[i]=-1;
 93     for(int i=0;i <= n;++i)
 94         tot[i]=1,fa[i]=-1;
 95 }
 96 int main()
 97 {
 98     scanf("%d%d",&n,&m);
 99     Init();
100     for(int i=1;i <= m;++i)
101     {
102         int u,v;
103         scanf("%d%d",&u,&v);
104         addEdge(u,v);
105     }
106     printf("%lld\n",Solve());
107 
108     return 0;
109 }
View Code

猜你喜欢

转载自www.cnblogs.com/violet-acmer/p/10946473.html
今日推荐