zoukankan      html  css  js  c++  java
  • BZOJ1093 最大半连通子图

    Description

      一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于图中任意
    两点u,v,存在一条u到v的有向路径或者从v到u的有向路径。若G'=(V',E')满足V'?V,E'是E中所有跟V'有关的边,
    则称G'是G的一个导出子图。若G'是G的导出子图,且G'半连通,则称G'为G的半连通子图。若G'是G所有半连通子图
    中包含节点数最多的,则称G'是G的最大半连通子图。给定一个有向图G,请求出G的最大半连通子图拥有的节点数K
    ,以及不同的最大半连通子图的数目C。由于C可能比较大,仅要求输出C对X的余数。

    Input

      第一行包含两个整数N,M,X。N,M分别表示图G的点数与边数,X的意义如上文所述接下来M行,每行两个正整
    数a, b,表示一条有向边(a, b)。图中的每个点将编号为1,2,3…N,保证输入中同一个(a,b)不会出现两次。N ≤1
    00000, M ≤1000000;对于100%的数据, X ≤10^8

    Output

      应包含两行,第一行包含一个整数K。第二行包含整数C Mod X.

    Sample Input

    6 6 20070603
    1 2
    2 1
    1 3
    2 4
    5 6
    6 4

    Sample Output

    3
    3
     
    正解:tarjan+DP
    解题报告:
      遥遥今天讲课讲了这道题,然后感觉这是最水的,就高兴地开了坑,调了半个晚上都没有发现为什么wa了。
      最后发现居然是有重边!!!!!!然后方案重复计算了,但我当时没有马上想出怎么判重,于是看了网上的题解发现可以用set,我真傻真的。
      做法其实挺简单,首先tarjan缩环,然后重构图,可以想到我们一定是在重构的图上选取一条链,使得链的点权和最大。DP可做。
     
     
      1 //It is made by jump~
      2 #include <iostream>
      3 #include <cstdlib>
      4 #include <cstring>
      5 #include <cstdio>
      6 #include <cmath>
      7 #include <algorithm>
      8 #include <ctime>
      9 #include <vector>
     10 #include <queue>
     11 #include <map>
     12 #include <set>
     13 #ifdef WIN32   
     14 #define OT "%I64d"
     15 #else
     16 #define OT "%lld"
     17 #endif
     18 using namespace std;
     19 typedef long long LL;
     20 const int MAXN = 100011;
     21 const int MAXM = 1000011;
     22 int MOD;
     23 int n,m,ecnt,ans,num;
     24 int first[MAXN],to[MAXM],next[MAXM];
     25 bool pd[MAXN];
     26 int dfn[MAXN],low[MAXN];
     27 int Stack[MAXN*2],top,belong[MAXN];
     28 int size[MAXN],cnt;
     29 int head[MAXN],ru[MAXN],f[MAXN];
     30 bool vis[MAXN];
     31 
     32 set<pair<int,int> >bst;//要有一个空格
     33 
     34 struct edge{
     35     int v,next;
     36 }e[MAXM];
     37 
     38 inline int getint()
     39 {
     40        int w=0,q=0;
     41        char c=getchar();
     42        while((c<'0' || c>'9') && c!='-') c=getchar();
     43        if (c=='-')  q=1, c=getchar();
     44        while (c>='0' && c<='9') w=w*10+c-'0', c=getchar();
     45        return q ? -w : w;
     46 }
     47 
     48 inline void dfs(int x){
     49     dfn[x]=++ecnt; low[x]=dfn[x];
     50     pd[x]=1; Stack[++top]=x;
     51     for(int i=first[x];i;i=next[i]) {
     52     int v=to[i];
     53     if(!dfn[v]) { dfs(v); if(low[v]<low[x]) low[x]=low[v]; }
     54     else if(pd[v]) low[x]=min(low[v],low[x]);
     55     }
     56     if(dfn[x]==low[x]){
     57     cnt++; size[cnt]++; belong[x]=cnt; pd[x]=0;
     58     while(Stack[top]!=x&&top) belong[Stack[top]]=cnt,pd[Stack[top]]=0,top--,size[cnt]++;
     59     top--;
     60     }
     61 }
     62 
     63 inline void tarjan(){
     64     ecnt=0;
     65     for(int i=1;i<=n;i++) if(!dfn[i]) dfs(i);
     66     ecnt=0;
     67     for(int i=1;i<=n;i++) {
     68     for(int j=first[i];j;j=next[j]) {
     69         int v=to[j];
     70         if(belong[i]!=belong[v]) {
     71         if(bst.find(make_pair(belong[i],belong[v]))!=bst.end()) continue;
     72         e[++ecnt].next=head[belong[i]]; head[belong[i]]=ecnt; e[ecnt].v=belong[v];
     73         ru[belong[v]]++;
     74         bst.insert(make_pair(belong[i],belong[v]));
     75         }
     76     }
     77     }
     78 }
     79 
     80 inline void DFS(int x){
     81     vis[x]=1;
     82     for(int i=head[x];i;i=e[i].next) {
     83     int v=e[i].v;
     84     if(!vis[v]) DFS(v);
     85     if(f[v]>f[x]) f[x]=f[v];
     86     }
     87     f[x]+=size[x];
     88 }
     89 
     90 inline void DFS2(int x){
     91     vis[x]=1;
     92     for(int i=head[x];i;i=e[i].next) {
     93     int v=e[i].v;
     94     if(!vis[v]) DFS2(v);
     95     //不能有重边!!!!!!
     96     if(f[x]==f[v]+size[x]) { dfn[x]+=dfn[v]; if(dfn[x]>=MOD) dfn[x]%=MOD; }
     97     }
     98     if(!head[x]) dfn[x]=1;
     99     if(f[x]==ans) { num+=dfn[x]; if(num>=MOD) num%=MOD; }
    100 }
    101 
    102 inline void DP(){    
    103     memset(vis,0,sizeof(vis));
    104     for(int i=1;i<=cnt;i++) if(!ru[i]) DFS(i),ans=max(ans,f[i]);
    105     memset(vis,0,sizeof(vis));  memset(dfn,0,sizeof(dfn));
    106     for(int i=1;i<=cnt;i++) 
    107     if(!ru[i]) {
    108         DFS2(i);
    109     }
    110     printf("%d
    %d",ans,num);
    111 }
    112 
    113 inline void work(){
    114     n=getint(); m=getint(); MOD=getint();
    115     int x,y;
    116     for(int i=1;i<=m;i++) {
    117     x=getint(); y=getint();
    118     next[++ecnt]=first[x]; first[x]=ecnt; to[ecnt]=y; 
    119     }
    120     tarjan();
    121     DP();
    122 }
    123 
    124 int main()
    125 {
    126   work();
    127   return 0;
    128 }
  • 相关阅读:
    [HNOI 2009] 有趣的数列
    [HAOI2015] 树上染色
    [BZOJ 2654] tree
    【图论 搜索】bzoj1064: [Noi2008]假面舞会
    【倍增】7.11fusion
    【二分 贪心】bzoj3477: [Usaco2014 Mar]Sabotage
    【计数】7.11跳棋
    概述「贪心“反悔”策略」模型
    复习计划里的低级错误
    【模拟】bzoj1686: [Usaco2005 Open]Waves 波纹
  • 原文地址:https://www.cnblogs.com/ljh2000-jump/p/5689717.html
Copyright © 2011-2022 走看看