考试的时候忘了缩点,人为dfs模拟缩点,没想到竟然跑了30分,RB爆发。。。

边是可以重复走的,所以在同一个强连通分量里,无论从那个点进入从哪个点出,所有的点一定能被一条路走到。 要使用缩点。

然后我们枚举每一条边,考虑如果将这条边反置的话,就是这条边的终点到1的点的权值(正向的)加上起点到1的点的权值(反向的);例:→→←→→

每个点到1的正向反向距离可以用两遍SPFA解决出来。

先使用tarjan缩点,记录每个点的权值,缩点后权值变为强连通分量中点的个数。缩完点之后重新建图,正向边存1,反向边存-1;

注意:在枚举每一条边求MAX时一定要判断它的起点和终点能否到达1。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
#define pos(i,a,b) for(int i=(a);i<=(b);i++)
#define pos2(i,a,b) for(int i=(a);i>=(b);i--)
#define N 501000
int n,m;
struct haha
{
       int next,to,w;
};
haha edgechu[N],edge[N];
int head[N],headchu[N],cnt=1,cntchu=1,cntt,hea;
int belong[N],low[N],dfn[N],ji=1,stack[N],instack[N];
int point[N];
void add(int u,int v,int w)
{
     edge[cnt].to=v;
     edge[cnt].next=head[u];
     edge[cnt].w=w;
     head[u]=cnt++;
}
void addchu(int u,int v,int w)
{
     edgechu[cntchu].to=v;
     edgechu[cntchu].next=headchu[u];
     edgechu[cntchu].w=w;
     headchu[u]=cntchu++;
}
void tarjan(int now)
{
     low[now]=dfn[now]=ji;
     ji++;
     stack[++hea]=now;
     instack[now]=1;
     for(int v=headchu[now];v;v=edgechu[v].next)
     {
             int i=edgechu[v].to;
             if(dfn[i]==-1)
             {
                tarjan(i);
                low[now]=min(low[now],low[i]);
             }
             else
               if(instack[i])
                  low[now]=min(low[now],dfn[i]);
     }
     if(low[now]==dfn[now])
     {
         cntt++;
         int temp;
         while(1)
         {
           temp=stack[hea--];
           belong[temp]=cntt;
           point[cntt]++;
           instack[temp]=0;
           //cout<<"temp="<<temp<<"  cntt="<<cntt<<endl;
           if(temp==now)
             break;
         }
     }
}
int diszheng[N],disfan[N];
int flag[N];
void spfazheng(int x)
{
     queue<int> q;
     pos(i,1,n)
       diszheng[i]=0;
     memset(flag,0,sizeof(flag));
     diszheng[x]=point[x];
     q.push(x);
     flag[x]=1;
     int k;
     while(!q.empty())
     {
        k=q.front();
        for(int v=head[k];v;v=edge[v].next)
        {
          int i=edge[v].to;
          if(edge[v].w>0&&diszheng[i]<diszheng[k]+point[i])
          {
              diszheng[i]=diszheng[k]+point[i];
              if(!flag[i])
              {
                 q.push(i);
                 flag[i]=1;
              }
          }
        }
        flag[q.front()]=0;
        q.pop();
     }
}
void spfafan(int x)
{
     queue<int> q;
     pos(i,1,n)
       disfan[i]=0;
     memset(flag,0,sizeof(flag));
     disfan[x]=point[x];
     q.push(x);
     flag[x]=1;
     int k;
     while(!q.empty())
     {
        k=q.front();
        for(int v=head[k];v;v=edge[v].next)
        {
          int i=edge[v].to;
          if(edge[v].w<0&&disfan[i]<disfan[k]+point[i])
          {
              disfan[i]=disfan[k]+point[i];
              if(!flag[i])
              {
                 q.push(i);
                 flag[i]=1;
              }
          }
        }
        flag[q.front()]=0;
        q.pop();
     }
}
struct qian
{
   int from,to;
}cun[N];
int road;
int ans;
int main()
{
    //freopen("cown.in","r",stdin);
    //freopen("cown.out","w",stdout);
    scanf("%d%d",&n,&m);
    memset(dfn,-1,sizeof(dfn));
    pos(i,1,m)
    {
       int x,y;
       scanf("%d%d",&x,&y);
       addchu(x,y,1);
    }
    pos(i,1,n)
      if(dfn[i]==-1)
       tarjan(i);
    pos(i,1,n)
       for(int v=headchu[i];v;v=edgechu[v].next)
       {
          int j=edgechu[v].to;
          if(belong[i]!=belong[j])
          {
             add(belong[i],belong[j],1);
             add(belong[j],belong[i],-1);
             cun[++road].from=belong[i];
             cun[road].to=belong[j];
          }
       }
    spfafan(belong[1]);spfazheng(belong[1]);
    /*pos(i,1,cntt)
      cout<<"diszheng[i]="<<diszheng[i]<<"   disfan[i]="<<disfan[i]<<endl;*/
    pos(i,1,road)
    {
      if(diszheng[cun[i].to]>0&&disfan[cun[i].from]>0)
       ans=max(ans,diszheng[cun[i].to]+disfan[cun[i].from]-point[belong[1]]);
       //cout<<"ans="<<ans<<endl;
    }
    printf("%d",ans);
    //while(1);
    return 0;
}

  

[Usaco2015 Jan]Grass Cownoisseur Tarjan缩点+SPFA的更多相关文章

  1. BZOJ 3887: [Usaco2015 Jan]Grass Cownoisseur tarjan + spfa

    Code: #include <bits/stdc++.h> #define setIO(s) freopen(s".in","r",stdin) ...

  2. BZOJ3887 [Usaco2015 Jan] Grass Cownoisseur 【tarjan】【DP】*

    BZOJ3887 [Usaco2015 Jan] Grass Cownoisseur Description In an effort to better manage the grazing pat ...

  3. [补档][Usaco2015 Jan]Grass Cownoisseur

    [Usaco2015 Jan]Grass Cownoisseur 题目 给一个有向图,然后选一条路径起点终点都为1的路径出来,有一次机会可以沿某条边逆方向走,问最多有多少个点可以被经过? (一个点在路 ...

  4. bzoj3887: [Usaco2015 Jan]Grass Cownoisseur

    题意: 给一个有向图,然后选一条路径起点终点都为1的路径出来,有一次机会可以沿某条边逆方向走,问最多有多少个点可以被经过?(一个点在路径中无论出现多少正整数次对答案的贡献均为1) =>有向图我们 ...

  5. BZOJ 3887/Luogu P3119: [Usaco2015 Jan]Grass Cownoisseur (强连通分量+最长路)

    分层建图,反向边建在两层之间,两层内部分别建正向边,tarjan缩点后,拓扑排序求一次1所在强连通分量和1+n所在强联通分量的最长路(长度定义为路径上的强联通分量内部点数和).然后由于1所在强连通分量 ...

  6. [Usaco2015 Jan]Grass Cownoisseur 图论 tarjan spfa

    先缩点,对于缩点后的DAG,正反跑spfa,枚举每条边进行翻转即可 #include<cstdio> #include<cstring> #include<iostrea ...

  7. BZOJ3887 [Usaco2015 Jan]Grass Cownoisseur[缩点]

    首先看得出缩点的套路.跑出DAG之后,考虑怎么用逆行条件.首先可以不用,这样只能待原地不动.用的话,考虑在DAG上向后走,必须得逆行到1号点缩点后所在点的前面,才能再走回去. 于是统计从1号点缩点所在 ...

  8. 洛谷—— P3119 [USACO15JAN]草鉴定Grass Cownoisseur || BZOJ——T 3887: [Usaco2015 Jan]Grass Cownoisseur

    http://www.lydsy.com/JudgeOnline/problem.php?id=3887|| https://www.luogu.org/problem/show?pid=3119 D ...

  9. [bzoj3887][Usaco2015 Jan]Grass Cownoisseur_trajan_拓扑排序_拓扑序dp

    [Usaco2015 Jan]Grass Cownoisseur 题目大意:给一个有向图,然后选一条路径起点终点都为1的路径出来,有一次机会可以沿某条边逆方向走,问最多有多少个点可以被经过?(一个点在 ...

随机推荐

  1. 新技术探究之 GraphQL

    What? GraphQL 是一种类似于 SQL 的结构化查询语言,由 facebook 于2012年创造,于2015年开源.SQL 在服务端定义,GraphQL 在客户端定义,也就是说 GraphQ ...

  2. c++有关构造函数和析构函数中调用虚函数问题

    今天看了一道迅雷的笔试题目,然后引起一段思考,题目如下: 下列关于虚函数的说法正确的是()A.在构造函数中调用类自己的虚函数,虚函数的动态绑定机制还会生效.B.在析构函数中调用类自己的虚函数,虚函数的 ...

  3. Servlet启动的时机

    Servlet启动的时机有两个:1.在用户第一次请求时:2.在web应用启动之时. 在web.xml 文件中配置 格式 <servlet> <servlet-name>**** ...

  4. 集成 ssh第一阶段

    1.添加spring支持,包含spring-hibernate和spring-struts2.添加struts支持,包含struts-spring3.添加hibernate支持,在spring配置文件 ...

  5. Hadoop各种进程的配置文件及其位置说明

    hdfs DameNode core-site.xml <!--设置主机的IP和端口--> <property> <name>fs.defaultFS</na ...

  6. hibernate总结-持续更新

    简介 hibernate官网:Hibernate Hibernate 是一个开放源代码的对象关系映射框架,它对 JDBC 进行了非常轻量级的对象封装,使得 Java 程序员可以随心所欲的使用对象编程思 ...

  7. 如何共享数据?- 每天5分钟玩转 Docker 容器技术(41)

    数据共享是 volume 的关键特性,本节我们详细讨论通过 volume 如何在容器与 host 之间,容器与容器之间共享数据. 容器与 host 共享数据 我们有两种类型的 data volume, ...

  8. java基础系列--Exception异常处理

    原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/7191280.html 1.概述 Java代码中的异常处理是非常重要的一环,从代码中可以看到 ...

  9. flume 1.7在windows下的安装与测试

    一.安装 安装java,配置环境变量. 安装flume,下载地址,下载后直接解压即可. 二.运行 创建配置文件:在解压后的文件 apache-flume-1.7.0-bin\conf下创建一个exam ...

  10. Es6 新增函数

    ====函数的扩展 -----ES6 之前,不能直接为函数的参数指定默认值,只能采用变通的方法. function log(x, y) { y = y || 'World'; console.log( ...