UESTC_邱老师的脑残粉 2015 UESTC Training for Graph Theory<Problem D>

D - 邱老师的脑残粉

Time Limit: 12000/4000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others)
 

邱老师的粉丝众多,每天邱老师都得面对粉丝们数不尽的邀约,邱老师一个人处理不过来,所以想请你帮忙。

假设某天有N个粉丝想和邱老师约,一旦某个粉丝成功地约上了邱老师,她就会发微博和朋友炫耀。一旦某个粉丝发现微博里有关于邱老师的消息,她都会转发。

如果当天内某个约上邱老师的粉丝发现微博里有其他粉丝和邱老师约会的消息,她就会很难堪,邱老师也会很难堪(显得邱老师不够专一)。为了避免这种尴尬的情况发生,邱老师每天只能从N个粉丝里选择一部分应约。

但是邱老师为了满足更多粉丝的愿望,邱老师能够从约会的粉丝中至多选择两名粉丝,迷惑她(们)当天停止使用微博(既不查看消息,也不转发消息),这样子能和邱老师约会的粉丝好像又变多了。但是选择哪两名粉丝才能使得能和邱老师约会的粉丝的数量达到最大?

Input

第一行两个整数N,M,表示当天有N个粉丝想和邱老师约会以及粉丝之间有M条关系。(1N,M5000)

接下来M行,每行表示两个数u,v表示第u个粉丝和第v个粉丝的微博是相互关注的。(1u,vN)

(相互关注指的是:u发的消息v都能看到,v发的消息u都能看到)

数据保证没有重边和自环

Output

输出邱老师当天最多能和多少个粉丝约会。

Sample input and output

Sample InputSample Output
5 4
1 2 
1 3
1 4
4 5
5

Hint

样例中,如果不迷惑粉丝的话,邱老师当天只能和1个粉丝约会(比如和2号粉丝约会),因为2号粉丝会发微博炫耀,1号粉丝看到后会转发,这样3号粉丝和4号粉丝看到1号的转发也会转发,这样5号粉丝也从4号粉丝那里看到了2号发的微博。

但是如果邱老师迷惑1号粉丝和4号粉丝让她俩当天停止使用微博的话,邱老师当天就能和5个粉丝约会辣!

解题报告:

 本题的数据很水,本题的数据很水,本题的数据很水,重要的事情说三遍,各位可以尝试二次直接贪,可2ms左右过

本题是一道tarjan算法题目.

首先我们第一个点需要枚举,why?考虑下面这种情况:

这个图既是边双连通,又是点双连通,第一个取的点程序是无法判断哪个更优的.

所以我们第一个点采用枚举的形式.

那么第二个点呢?

注意到第二个点之后我们并不能继续操作,所以第二点的选取我们用贪心.

这样,算法框架就出来了:

  1. 枚举每个可能的第一个点
  2. 对切割这个点后的图跑tarjan,这里我采用的是割桥,若u – v是割桥,则val[u] ++ , val[v] ++
  3. 我们去掉val值最大的点,然后跑一次连通分量,并更新答案

复杂度: O ( n * ( n + m ) * 2 )

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
#define pb push_back
using namespace std;
const int maxn = 5e3 + 50;
vector<int>E[maxn];
int n,m,T,new_time[maxn],low[maxn];
int is_cut[maxn] , cut_vertx1 , cut_vertx2 , ans = 0 ,ptr;
bool vis[maxn]; //染色集合 

int tarjan_dfs(int cur,int pre)
{
   new_time[cur] = low[cur] = T++;
   for(int i = 0 ; i < E[cur].size() ; ++ i)
    {
        int nextnode = E[cur][i];
        if (nextnode == cut_vertx1) continue; //枚举的第一次去掉的点
        ptr = cur;
        if (!new_time[nextnode]) //树边 
         {
             int lowv = tarjan_dfs(nextnode,cur);
             if (lowv > new_time[cur])
               {
                  is_cut[cur] ++ , is_cut[nextnode] ++ ;    
              }
            low[cur] = min(low[cur],lowv);
         }
        else if (new_time[nextnode] < new_time[cur] && nextnode != pre)  //反向边
         low[cur] = min(low[cur],new_time[nextnode]);
    }
   return low[cur];
}


void colour_map(int cur)
{
   vis[cur] = true;
   for(int i = 0 ; i < E[cur].size() ; ++ i)
    {
        int nextnode = E[cur][i];
        if (!vis[nextnode] && nextnode != cut_vertx1 && nextnode != cut_vertx2)
         colour_map(nextnode);
    }
}

void updata_ans(int x,int y)
{
   cut_vertx1 = x , cut_vertx2 = y;
   int tot = 0;
   memset(vis,false,sizeof(vis));
   for(int i = 1 ; i <= n ; ++ i)
    if (!vis[i])
     {
         if (i != cut_vertx1 && i != cut_vertx2)
          colour_map(i);
         tot++;
     }
   ans = max(ans,tot);
}

void slove()
{
  for(int tt = 1 ; tt <= n ; ++ tt)
   {
         cut_vertx1 = tt;
         memset(is_cut,0,sizeof(is_cut));
      memset(new_time,0,sizeof(new_time));
      T = 1;
      if (tt == 1)
       ptr = 2;
      else
       ptr = 1;
         for(int i = 1 ; i <= n ; ++ i)
       if (!new_time[i] && i != cut_vertx1)
        tarjan_dfs(i,0);
      int maxlen = 0;
      for(int i = 1 ; i <= n ; ++ i)
       if (is_cut[i] >= maxlen)
        {
            maxlen = is_cut[i];
            ptr = i;
        }
      updata_ans(tt,ptr);
   }
}


int main(int argc,char *argv[])
{
  scanf("%d%d",&n,&m);
  for(int i = 1 ; i <= m ; ++ i)
   {
         int u,v;
         scanf("%d%d",&u,&v);
         E[u].pb(v) , E[v].pb(u);
   }
  slove();
  printf("%d
",ans);
  return 0;
}
原文地址:https://www.cnblogs.com/Xiper/p/4570653.html