【高铁游中国】第37站-婺源|去婺源看油菜花,或是赏秋景,你都去对地方了啊?|旅游知识坊

大千世界自然跟人文旅游专题

可以结合当下首博客进行复习:http://www.cnblogs.com/z360/p/7363034.html

微信公众号—旅游知识坊

       一、强连通分量、缩点

(更多更新文章,请关注微信公众号)

习题:

洛谷——P2746 [USACO5.3]校园网Network of Schools

传送门

图片 1图片 2

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 1010 
using namespace std;
bool vis[N];
int n,m,s1,s2,tot,tim,sum,top,ans1,ans2;
int in[N],out[N],low[N],dfn[N],head[N],stack[N],belong[N];
int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
struct Edge
{
    int to,next;
}edge[N];
int add(int x,int y)
{
    tot++;
    edge[tot].to=y;
    edge[tot].next=head[x];
    head[x]=tot;
}
int tarjan(int x)
{
    dfn[x]=low[x]=++tim;
    stack[++top]=x,vis[x]=true;
    for(int i=head[x];i;i=edge[i].next)
    {
        int t=edge[i].to;
        if(vis[t]) low[x]=min(low[x],dfn[t]);
        else if(!dfn[t]) tarjan(t),low[x]=min(low[x],low[t]);
    }
    if(low[x]==dfn[x])
    {
        sum++;belong[x]=sum;
        for(;stack[top]!=x;top--)
        {
            vis[stack[top]]=false;
            belong[stack[top]]=sum;
        }
        top--,vis[x]=false;
    }
}
int shink_point()
{
    for(int i=1;i<=n;i++)
     for(int j=head[i];j;j=edge[j].next)
     {
         int t=edge[j].to;
         if(belong[i]!=belong[t])
          in[belong[t]]++,out[belong[i]]++;
     }
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++)
    {
        while(1)
        {
            m=read();
            if(m==0) break;
            add(i,m);
        }
    }
    for(int i=1;i<=n;i++)
     if(!dfn[i]) tarjan(i);
    shink_point();
    for(int i=1;i<=sum;i++)
    {
        if(in[i]==0) s1++;
        if(out[i]==0) s2++;
     } 
    if(sum==1) ans2=0;
    else ans2=max(s1,s2);
    ans1=s1;
    printf("%d\n%d",ans1,ans2);
    return 0;
}

tarjan求强连通分量

粗总:1.极度少吃几乎个人知道即便可以成功让具备的丁都知晓消息,最少知道之食指的多寡即为缩了点后称读也零星底点的个数

    2.顶少在几久边就好假设这个图变成一个强连通图,加的尽头的条数即为缩了点后Max(入读为零星的触发之个数,出度为零星之点的个数)

poj——3177 Redundant Paths

传送门

请求一个不管往图于加入多少条边后成边对连过渡图。跟方的类型差不多相同,只不过是一个啊来往图,一个为无为图。既然类型相同,那么我们以同样之合计来开就道题,首先我们先tarjan缩点,然后统计称读也0点的触及的个数。有同学肯定使咨询了,无向图什么,怎么可能适合读也0也,而且若怎么掌握凡是入读还是初读的哟,并且tarjan缩点的前提不是来往图为?这是随便往图什么,怎么缩点?
      这即将归功给:if(i==(1^pre))
continue; 对,他是为此半漫漫边,但是我们这个地方只于他移动相同条边,这样不纵跟生于图缩点一样了啊?!不亮凡是入读还是出度,那么直接统计度数为2底触及的个数。

图片 3图片 4

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 5005
using namespace std;
bool vis[N];
long long  n,m,x,y,ans,tot=1,tim,sum,top;
long long du[N],dfn[N],low[N],stack[N],belong[N];
long long head[20010];
int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-') f=-1; ch=getchar();}
    while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
struct Edge
{
    int from,next,to;
}edge[20010];
void add(int x,int y)
{
    tot++;
    edge[tot].to=y;
    edge[tot].next=head[x];
    head[x]=tot;
}
int tarjan(int now,int pre)
{
    dfn[now]=low[now]=++tim;
    stack[++top]=now; 
    for(int i=head[now];i;i=edge[i].next)
    {
        int t=edge[i].to;
        if(i==(1^pre)) continue;
        if(!dfn[t]) tarjan(t,i),low[now]=min(low[now],low[t]);
        else low[now]=min(low[now],dfn[t]);
    }
    if(low[now]==dfn[now])
    {
        sum++; belong[now]=sum;
        for(;stack[top]!=now;top--)
          belong[stack[top]]=sum;
        top--;
    }
}
int main()
{
    n=read(),m=read();
    for(int i=1;i<=m;i++)
     x=read(),y=read(),add(x,y),add(y,x);
    tarjan(1,0);
    for(int i=1;i<=n;i++)
     for(int j=head[i];j;j=edge[j].next)
      if(belong[i]!=belong[edge[j].to]) du[belong[i]]++,du[belong[edge[j].to]]++;
    for(int i=1;i<=n;i++)
     if(du[i]==2) ans++;
    printf("%d",(ans+1)>>1);
    return 0;
}

任向图缩点

本文为出游知识坊的第37首观察文章

洛谷——P2661 信息传递 && cogs619. [金陵中学2007] 传话

传送门 

图片 5信息传送tarjan判环

图片 6传话:图片 7

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 10010
using namespace std;
bool vis[N];
int n,m,x,y,tot,tim,sum,top;
int s[N],dfn[N],low[N],head[N],stack[N],belong[N];
int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
struct Edge
{
    int to,next;
}edge[N];
int add(int x,int y)
{
    tot++;
    edge[tot].to=y;
    edge[tot].next=head[x];
    head[x]=tot;
}
int tarjan(int x)
{
    dfn[x]=low[x]=++tim;
    stack[++top]=x;vis[x]=true;
    for(int i=head[x];i;i=edge[i].next)
    {
        int t=edge[i].to;
        if(vis[t]) low[x]=min(low[x],dfn[t]);
        else if(!dfn[t]) tarjan(t),low[x]=min(low[x],low[t]);
    }
    if(low[x]==dfn[x])
    {
        sum++;belong[x]=sum,s[sum]++;
        for(;stack[top]!=x;top--)
        {
            s[sum]++;
            vis[stack[top]]=false;
            belong[stack[top]]=sum;
        }
        vis[x]=false;top--;
    }
}
int main()
{
    freopen("messagez.in","r",stdin);
    freopen("messagez.out","w",stdout);
    n=read(),m=read();
    for(int i=1;i<=m;i++)
    {
        x=read(),y=read();
        add(x,y);
    }
    for(int i=1;i<=n;i++)
     if(!dfn[i]) tarjan(i);
    for(int i=1;i<=n;i++)
     if(s[belong[i]]==1) printf("F\n");
     else printf("T\n");
    return 0;
}

tarjan判环

tarjan判环,可以为此来化解以下问题   1.一个总人口发的音信是否能够传为好
 2.等同森口玩游戏,如果协调之信息给别人告诉那么游戏结束,问尽少进行的轮数,用tarjan求最小环中的触及的个数

《高铁游中国》系列之第37站-婺源

洛谷—— P3469 [POI2008]BLO-Blockade

传送门

题解:我们解割掉一个点后,能够对整张图的免连过渡有序对促成影响之终将也割点,因此,我们因而tarjan处理,我们拿是图看成一颗树,将触及割掉后不连贯的平稳对为夫热点树内的触及之·个数*此点大中的接触之个数。这样我们以能查出他们之间莫可知循环不断的罗列就是他的生父节点内之个数*塔子树节点内的个数、。即ans【i】=t*(n-t-1)
t=size[i]
这样我们恳请来了从该点外无克相互到达的对数。最后更增长由于斯点割去矣,因此这点不能到达所有的触及。最后乘2

图片 8图片 9

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 500010
#define ll long long
using namespace std;
ll ans[N];
int n,m,x,y,tot,tim;
int dfn[N],low[N],head[N],size[N];
int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
struct Edge
{
    int to,next;
}edge[N<<1];
int add(int x,int y)
{
    tot++;
    edge[tot].to=y;
    edge[tot].next=head[x];
    head[x]=tot;
}
int tarjan(int x)
{
    int z=0;size[x]=1;
    dfn[x]=low[x]=++tim;
    for(int i=head[x];i;i=edge[i].next)
    {
        int t=edge[i].to;
        if(!dfn[t])
        {
            tarjan(t);size[x]+=size[t];
            low[x]=min(low[x],low[t]);
            if(dfn[x]<=low[t])
            {
                ans[x]+=(ll)z*size[t];
                z+=size[t];
            }
        }
        else low[x]=min(low[x],dfn[t]);
    }
    ans[x]+=(ll)z*(n-z-1);
}
int main()
{
    n=read(),m=read();
    for(int i=1;i<=m;i++)
    {
        x=read(),y=read();
        add(x,y),add(y,x);
    }
    tarjan(1);
    for(int i=1;i<=n;i++)
     printf("%lld\n",(ans[i]+n-1)<<1);
    return 0;
}

割掉一个点后,不连通的对数

 

极给欢迎之牛类的类似的题材,我们需要tarjan缩点然后初度为零星之点即为极其让欢迎之牛

              二、割边、割点

习题:

作者:航海家

洛谷——P3225 [HNOI2012]矿场搭建

传送门

题解:我们渴求最少打几单逃生处才能够如任意一个地方炸了具备的食指犹能够逃生。我们要以割点炸掉以后,这个图被得会化为少数单对连过渡分量,我们可理解如果一个双连通分量中没割点,那么我们得修建有限个逃生处扎了一个还会去其它一个;如果总是一个割点,我们一味需要在双连通图中盖一个虽好了,炸了割点还能够逃生;如果链接两只,那个无论炸那个我们都能够透过外一个逃生

图片 10图片 11

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 510
using namespace std;
long long ans2;
bool vis[N],cut_point[N],cut_edge[N];
int head[N<<1],dfn[N],low[N],belong[N];
int n,m,x,y,s,tim,cut,tot,sum,cnt,ans1;
int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
struct Edge
{
    int to,next;
}edge[N<<1];
int add(int x,int y)
{
    tot++;
    edge[tot].to=y;
    edge[tot].next=head[x];
    head[x]=tot;
}
int tarjan(int x,int pre)
{
    int sum=0;bool boo=false;
    dfn[x]=low[x]=++tim;
    for(int i=head[x];i;i=edge[i].next)
    {
        int t=edge[i].to;
        if((1^i)==pre) continue;
        if(!dfn[t])
        {
            sum++;tarjan(t,i);
            low[x]=min(low[x],low[t]);
            if(low[t]>dfn[x]) cut_edge[i/2]=true;
            if(low[t]>=dfn[x]) boo=true;    
        }
        else low[x]=min(low[x],dfn[t]);    
    }    
    if(pre==-1){if(sum>1) cut_point[x]=true;}
    else if(boo) cut_point[x]=true;
}
int begin()
{
    n=tim=ans1=0;tot=ans2=1;
    for(int i=1;i<=N;i++)
    {
        vis[i]=cut_point[i]=0;
        dfn[i]=low[i]=belong[i]=0;
     } 
    memset(head,0,sizeof(head));
    memset(edge,0,sizeof(edge));
}
int dfs(int x)
{
    s++;vis[x]=true;belong[x]=sum;
    for(int i=head[x];i;i=edge[i].next)
    {
        int t=edge[i].to;
        if(cut_point[t]&&belong[t]!=sum)  cut++,belong[t]=sum;
        if(!vis[t]&&!cut_point[t]) dfs(t);
    }
}
int main()
{
    while(1)
    {
        m=read();
        if(m==0) break;begin();
        for(int i=1;i<=m;i++)
        {
            x=read(),y=read();
            add(x,y),add(y,x);
            n=max(n,max(x,y));
        }
        for(int i=1;i<=n;i++)
         if(!dfn[i]) tarjan(i,-1);
        sum=0;
        for(int i=1;i<=n;i++)
        {
            if(vis[i]||cut_point[i]) continue;
            s=cut=0,sum++;dfs(i);
            if(!cut) ans1+=2,ans2*=(long long)(s*(s-1))>>1;
            if(cut==1) ans1++,ans2*=(long long)s;
        }
        printf("Case %d: %d %lld\n",++cnt,ans1,ans2);
    }
    return 0;
}

tarjan+dfs

当损坏一个碰或者同等漫长边就非可知是图联通的时刻,就要求割点割边

《高铁游中国》系列简介

POJ——SPF

传送门

求删这个割点后发出几只强连通子图

缓解这无异于类似题材的下我们好事先要出割点,我们发理解low值相同的触及当一个强连通分量里,然后我们得以请求与该割点相连的点的low值不同之个数

图片 12图片 13

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 10010
using namespace std;
int n,x,y,tot,tim,cnt,sum;
int dfn[N],low[N],head[N];
bool flag,vis[N],cut_point[N];
int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
struct Edge
{
    int from,next,to;
}edge[N*200];
void add(int x,int y)
{
    tot++;
    edge[tot].to=y;
    edge[tot].next=head[x];
    head[x]=tot;
}
int begin()
{
    tim=0,tot=1;flag=false;
    memset(head,0,sizeof(head));
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(cut_point,0,sizeof(cut_point));    
}
int tarjan(int x,int pre)
{
    int s=0; bool boo=false;
    dfn[x]=low[x]=++tim;
    for(int i=head[x];i;i=edge[i].next)
    {
        if((i^1)==pre) continue;
        int t=edge[i].to;
        if(!dfn[t])
        {
            s++,tarjan(t,i);
            low[x]=min(low[t],low[x]);
            if(dfn[x]<=low[t]) boo=true;
        }
        else low[x]=min(low[x],dfn[t]);
    }
    if(pre==-1){if(s>1) cut_point[x]=true;}
    else if(boo) cut_point[x]=true;
}
int main()
{
    while(1)
    {
        x=read();if(x==0) break;
        begin();y=read(),add(x,y),add(y,x);
        n=max(n,max(x,y)),cnt++;
        while(1)
        {
            x=read();
            if(x==0) break;
            y=read(),add(x,y),add(y,x);
            n=max(n,max(x,y));
        }
        printf("Network #%d\n",cnt);
        tarjan(1,-1);
        for(int i=1;i<=n;i++)
         if(cut_point[i])
         {
             sum=0;flag=true;
            memset(vis,0,sizeof(vis));
             for(int j=head[i];j;j=edge[j].next)
             {
                 int t=edge[j].to;
                 if(vis[low[t]]) continue;
                 vis[low[t]]=true,sum++;
            }
            printf("  SPF node %d leaves %d subnets\n",i,sum);
         }
        if(!flag) printf("  No SPF nodes\n");
        printf("\n");
    }
    return 0;
}

剔除割点后联通子图的个数

 

 

              三、最小生成树

   
本专题为笔者所当的市——成都市吗起点,沿着高铁走遍全国100只观光都(线路不更,一久线走了事),每幢都市一个谜,一个主题,一首稿子,深度挖掘该城之当然人文旅游文化。

T3 BZOJ——1821: [JSOI2010]Group 部落划分 Group

题解:要以立即n各部落全部连接起来需要n-1条边,我们若用其划分成m个部落,也就是说我们设发生m个部落不能够让连接起来,我们而先期以离开有点的一定量只群体先连起来,这就算正好是太小生成树的思想,所以要是想到最小生成树也容易。我们以立即m个部落连起来刚刚是故m-1条边,也就是说我们拿除了那m个部落连起来,恰好是只要就此n-1-(m-1)也即是n-m条边,然后马上m部落间的顶小之距离便n-m+1条边的尺寸了

图片 14图片 15

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 1010
using namespace std;
double ans;
int n,k,x,y,s,fx,fy,sum,fa[N],xx[N],yy[N];
int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
struct Edge
{
    int x,y;
    double z;
}edge[N*N];
int cmp(Edge a,Edge b)
{return a.z<b.z;}
int find(int x)
{
    if(x==fa[x]) return  x;
    fa[x]=find(fa[x]);
    return fa[x];
}
int main()
{
    n=read(),k=read();
    for(int i=1;i<=n;i++) xx[i]=read(),yy[i]=read();
    for(int i=1;i<=n;i++)
     for(int j=1;j<=n;j++)
      if(i!=j)
      {
          ++s;
          edge[s].x=i;
          edge[s].y=j;
          edge[s].z=sqrt((double)pow(xx[i]-xx[j],2)+(double)pow(yy[i]-yy[j],2));
      }
    for(int i=1;i<=n;i++) fa[i]=i;
    sort(edge+1,edge+1+s,cmp);
    for(int i=1;i<=s;i++)
    {
        x=edge[i].x,y=edge[i].y;
        fx=find(x),fy=find(y);
        if(fa[fx]==fy) continue;
        fa[fx]=fy;sum++;
        if(sum==n-k+1) {ans=edge[i].z;break;}
    }
    printf("%.2lf",ans);
    return 0;
}

告用n个群体划分成m个,使这些群体里的太短距离最要命,求即m部落间最短距离

    不是游记,不是攻略,而是发生程度有态度发生分析的城市旅游考察!

cogs——2419. [HZOI 2016]公路修建2

 题解:现选k种A道路,然后在跑不过小生成树,求最好小生成树最长边

图片 16图片 17

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define N 210000
using namespace std;
int n,m,x,y,k,z1,z2,fx,fy,sum,ans,fa[N];
int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*f;
}
struct Edge
{
    int x,y,z1,z2;
}edge[N];
int cmp1(Edge a,Edge b)
{return a.z1<b.z1;}
int cmp2(Edge a,Edge b)
{return a.z2<b.z2;}
int find(int x)
{
    if(x==fa[x]) return  x;
    fa[x]=find(fa[x]);
    return fa[x];
}
int main()
{
    freopen("hzoi_road2.in","r",stdin);
    freopen("hzoi_road2.out","w",stdout);
    n=read(),k=read(),m=read();
    for(int i=1;i<m;i++)
    {
        x=read(),y=read(),z1=read(),z2=read();
        edge[i].x=x;
        edge[i].y=y;
        edge[i].z1=z1;
        edge[i].z2=z2;
    }
    for(int i=1;i<=n;i++) fa[i]=i;
    sort(edge+1,edge+m+1,cmp1);
    for(int i=1;i<=m;i++)
    {
        if(k==0) break;
        x=edge[i].x,y=edge[i].y;
        fx=find(x),fy=find(y);
        fa[fx]=fy;sum++;
        ans=max(ans,edge[i].z1);
        if(sum==k)break;
    }
    sort(edge+1,edge+1+m,cmp2);
    for(int i=1;i<=m;i++)
    {
        x=edge[i].x,y=edge[i].y;
        fx=find(x),fy=find(y);
        if(fx==fy) continue;
        fa[fx]=fy;
        ans=max(ans,edge[i].z2);
    }
    printf("%d",ans);
    return 0;
}

以n个村庄里有点儿种植道路,求至少用k种A道路的假设所有道路连通的顶短距离中的极丰富路

【合福高铁】

HDU——3072 Intelligence System

题解:看到是开首先想到的便是tarjan缩点然后求最小生成树吧,但是咱会发现wa掉,为什么,因为我们是地方是发生向图,如果使用最小生成树使他们在一个连查集里,但是实际这几只点或者不接入,所以我们所以贪心的思,求出于每个点联通的最短路的长,然后加上’

图片 18图片 19

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 300010
#define maxn 0x7fffffff
using namespace std;
bool vis[N];
long long ans;
int n,m,x,y,z,s,tot,num,sum,top,tim;
int fa[N],low[N],dfn[N],cost[N],stack[N],head[N],belong[N];
int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
struct Edge
{
    int to,dis,next;
}edge[N];
struct Edde
{
    int to,dis,next;
}edde[N];
int add(int x,int y,int z)
{
    tot++;
    edge[tot].to=y;
    edge[tot].dis=z;
    edge[tot].next=head[x];
    head[x]=tot;
}
void begin()
{
    s=0,tim=0,sum=0,tot=0;
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(vis,0,sizeof(vis));
    memset(head,0,sizeof(head));
    memset(belong,0,sizeof(belong));
}
void tarjan(int now)
{
    dfn[now]=low[now]=++tim;
    stack[++top]=now; vis[now]=true;
    for(int i=head[now];i;i=edge[i].next)
    {
        int t=edge[i].to;
        if(vis[t]) low[now]=min(low[now],dfn[t]);
        else if(!dfn[t]) tarjan(t),low[now]=min(low[now],low[t]);
    }
    if(low[now]==dfn[now])
    {
        sum++;belong[now]=sum;
        for(;stack[top]!=now;top--)
        {
            int x=stack[top];
            belong[x]=sum;vis[x]=false;
        }
        vis[now]=false;top--;
    }
}
void work()
{
    ans=0;
    for(int i=1;i<=n;i++)
      for(int j=head[i];j;j=edge[j].next)
      {
          int t=edge[j].to;
          if(belong[i]!=belong[t])
            cost[belong[t]]=min(cost[belong[t]],edge[j].dis);    
     } 
   for(int i=1;i<=sum;i++)
    if(cost[i]!=maxn) ans+=(long long)cost[i];
   printf("%lld\n",ans);
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        begin();
        for(int i=1;i<=n;i++) cost[i]=maxn;
        for(int i=1;i<=m;i++)
          x=read(),y=read(),z=read(),add(x+1,y+1,z);
        for(int i=1;i<=n;i++)
         if(!dfn[i]) tarjan(i);
        work();
    }
    return 0;
}

吁用n个点连通的尽短路的长度,如果存在几乎单点于缠绕中,那么就几乎独点并过渡不待花

G1517,黄山北-婺源,历时21分

洛谷——P2330 [SCOI2005]无暇的城

题解:最少的征途条数即为极其小生成树需要加的边的条数即为n-1。第二叩问吗呼吁最好小生成树中之最好长边

图片 20图片 21

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 50010
using namespace std;
int n,m,x,y,z,fx,fy,sum,fa[N],ans1,ans2;
int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
struct Edge
{
    int x,y,z;
}edge[N<<1];
int cmp(Edge a,Edge b)
{return a.z<b.z;}
int find(int x)
{
    if(x==fa[x]) return x;
    fa[x]=find(fa[x]);
    return fa[x];
}
int main()
{
    n=read(),m=read();
    for(int i=1;i<=m;i++)
    {
        edge[i].x=read();
        edge[i].y=read();
        edge[i].z=read();
    }
    sort(edge+1,edge+1+m,cmp);
    for(int i=1;i<=n;i++) fa[i]=i;
    for(int i=1;i<=m;i++)
    {
        x=edge[i].x,y=edge[i].y;
        fx=find(x),fy=find(y);
        if(fx==fy) continue;
        fa[fx]=fy;sum++;
        ans2=max(ans2,edge[i].z);
        if(sum==n-1) break;
    }ans1=n-1;
    printf("%d %d",ans1,ans2);
    return 0;
}

拿n个点连通,最少之征程的条数,分值最可怜的那么长道路的分值

 

在皖浙赣交界处,有这么一个神奇的地方,它不光起粉墙黛瓦的徽州古民居、小桥流水的田园风光,还有金灿灿的菜花田、摄人心魄的美妙秋景,被称呼“中国无与伦比得意乡村”。

         四、最短路

此间,就是婺源。

1.极端短路模板题

婺源一年四季都出两样的美景,尤以年度两季也盛。春季观油菜花海、品春茶,秋季赏红叶、看晒秋、拍摄晨雾。东线、西线、北线等各级景点,遍布于农村村落,可谓处处是情景。

洛谷——P2047 社交网络

Floyd预处理打s到t最短路的条数,当半单点之间有边相连的时咱们她的卓绝短缺里程得条数初始化为1,然后我们跑Floyd,当于s到t的无比缺里程要由k来更新的时候,那么自从s到t的最好短路的条数即为打s到k最短路的条数*自打k到t最短路的·条数,dis[s][k]+dis[k][t]=dis[s][t],那么最好短路的条数就如于丰富从s到k最短路的条数*自k到t最短路的·条数

图片 22图片 23

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 210
#define maxn 999999
using namespace std;
double ans[N],f[N][N];
int n,m,x,y,z,dis[N][N];
int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
int main()
{
    n=read(),m=read();
    for(int i=1;i<=n;i++)
     for(int j=1;j<=n;j++)
      dis[i][j]=(i!=j)*maxn;
    for(int i=1;i<=m;i++)
    {
        x=read(),y=read(),z=read();
        f[x][y]=f[y][x]=1;
        dis[x][y]=dis[y][x]=z;
    }
    for(int k=1;k<=n;k++)
     for(int i=1;i<=n;i++)
      for(int j=1;j<=n;j++)
       if(dis[i][j]>dis[i][k]+dis[k][j])
       {
           f[i][j]=f[i][k]*f[k][j];
           dis[i][j]=dis[i][k]+dis[k][j];
       }
       else 
        if(dis[i][j]==dis[i][k]+dis[k][j])
         f[i][j]+=f[i][k]*f[k][j];
    for(int k=1;k<=n;k++)
     for(int i=1;i<=n;i++)
      for(int j=1;j<=n;j++)
       if(i!=k&&k!=j&&dis[i][j]==dis[i][k]+dis[k][j]&&f[i][j])
        ans[k]+=(double)f[i][k]*f[k][j]/f[i][j];
    for(int i=1;i<=n;i++)
     printf("%.3lf\n",ans[i]);
    return 0;
}

请于s到t的绝短路的条数及从求经过一个触及之太短路的条数

面多而散的处处景点,春秋两季前往婺源,在个别的流年外,该如何游其精髓吧?

洛谷——P2966 [USACO09DEC]牛收费路径Cow Toll Paths

题意:点来点权,边发边权,从一个触及交任何一个碰的开销,是通过的所有道路的过路费之和,加上经过的具有的都会(包括起点与终点)的过路费的绝酷价值,给定k个询问,求于s到t的太特别价值,如无连过渡输出-1

题解:Floyd,将点权进行排序,然后跑Floyd,我们以挨家挨户跑Floyd的时节保证k=n是的k的点权最特别,也就是说这里我们于更新i到j这长达路子的当儿依次是若之中游节点的点权最可怜,这样保证中节点的点权最老,这样即便不要摸每条路上的极酷点权了

图片 24图片 25

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define N 300
#define maxn 9999999
using namespace std;
int n,m,x,y,z,p,dy[N],dis[N][N],f[N][N];
int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
struct Node
{
    int c,num;
}node[N];
int cmp(Node a,Node b)
{return a.c<b.c;}
int main()
{
    n=read(),m=read(),p=read();
    for(int i=1;i<=n;i++) node[i].c=read(),node[i].num=i;
    sort(node+1,node+1+n,cmp);
    for(int i=1;i<=n;i++) dy[node[i].num]=i;
    for(int i=1;i<=n;i++)
     for(int j=1;j<=n;j++)
      f[i][j]=dis[i][j]=maxn;
    for(int i=1;i<=n;i++) f[i][i]=0;
    for(int i=1;i<=m;i++)
    {
        x=read(),y=read(),z=read();
        x=dy[x],y=dy[y];
        f[x][y]=f[y][x]=min(f[x][y],z);
    }
    for(int k=1;k<=n;k++)
     for(int i=1;i<=n;i++)
      for(int j=1;j<=n;j++)
      {
          f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
        dis[i][j]=min(dis[i][j],f[i][j]+max(max(node[i].c,node[k].c),node[j].c)); 
      }
    while(p--)
    {
        x=read(),y=read();
        x=dy[x],y=dy[y];
        if(dis[x][y]>=maxn) printf("-1\n");
        else printf("%d\n",dis[x][y]);
    }
    return 0;
}

吁于一个碰到其他一个沾之太短路的,定义为边权+最可怜点权

今日的文章,就带您活动上前《高铁游中国》系列的第37站——婺源,欣赏年两季婺源旅游之6颇精华景点。

洛谷——P1629 邮递员送信

题解:从1点及每个点的顶缺里程老好求,那么从每个点及1触及的极短路的长短也?我们建造反朝度,那么先可以反向到达1点之接触我们都得以自1点达,那么我们当走一边spfa,求出由1点交任何接触的极度短路程就为自其它接触至1沾之不过短路的尺寸。

图片 26图片 27

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 300010
#define maxn 999999
using namespace std;
queue<int>q;
bool vis[N];
long long ans;
int n,m,x,y,z,tot,tot1;
int dis[N],dis1[N],head[N],head1[N];
int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
struct Edge
{
    int to,dis,next;
}edge[N],edge1[N];
int add(int x,int y,int z)
{
    tot++;
    edge[tot].to=y;
    edge[tot].dis=z;
    edge[tot].next=head[x];
    head[x]=tot;
}
int add1(int x,int y,int z)
{
    tot1++;
    edge1[tot1].to=y;
    edge1[tot1].dis=z;
    edge1[tot1].next=head1[x];
    head1[x]=tot1;
}
int spfa(int s)
{
    for(int i=1;i<=n;i++) dis[i]=maxn,vis[i]=false;
    q.push(s),vis[s]=true,dis[s]=0;
    while(!q.empty())
    {
        x=q.front();q.pop(),vis[x]=false;
        for(int i=head[x];i;i=edge[i].next)
        {
            int t=edge[i].to;
            if(dis[t]>dis[x]+edge[i].dis)
            {
                dis[t]=dis[x]+edge[i].dis;
                if(vis[t]) continue;
                q.push(t),vis[t]=false;
            }
        }
    }
}
int spfa1(int s)
{
    for(int i=1;i<=n;i++) dis1[i]=maxn,vis[i]=false;
    q.push(s),vis[s]=true,dis1[s]=0;
    while(!q.empty())
    {
        x=q.front();q.pop(),vis[x]=false;
        for(int i=head1[x];i;i=edge1[i].next)
        {
            int t=edge1[i].to;
            if(dis1[t]>dis1[x]+edge1[i].dis)
            {
                dis1[t]=dis1[x]+edge1[i].dis;
                if(vis[t]) continue;
                q.push(t),vis[t]=false;
            }
        }
    }
}
int main()
{
    n=read(),m=read();
    for(int i=1;i<=m;i++)
    {
        x=read(),y=read(),z=read();
        add(x,y,z),add1(y,x,z);
    }
    spfa(1),spfa1(1);
    for(int i=2;i<=n;i++)
     ans+=(long long)dis[i]+dis1[i];
    printf("%lld",ans);
    return 0;
}

求于1点交具备点然后在从所有点返回1碰之最好短路的尺寸,注意我们一样次于独自会达一个点

婺源概览

洛谷——P1608 路径统计

题解:统计最缺乏路径条数的时候,如果手上点t是由于x更新的,那么到t的绝短路程长数=到达x点的太差里程条数;如果dis[t]=dis[x]+edge[i].dis;最缺少路径+到达x点的极端短路的条数

图片 28图片 29

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 3010
#define maxn 999999
using namespace std;
queue<int>q;
bool vis[N];
int n,m,x,y,z,tot,sum[N],dis[N],f[N][N];
int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
int spfa(int s)
{
    for(int i=1;i<=n;i++) dis[i]=maxn,vis[i]=false,sum[i]=1;
    dis[s]=0,vis[s]=true,q.push(s);
    while(!q.empty())
    {
        x=q.front(),q.pop();vis[x]=false;
        for(int t=1;t<=n;t++)
          if(f[x][t])
            if(dis[t]>dis[x]+f[x][t])
            {
                dis[t]=dis[x]+f[x][t];
                sum[t]=sum[x];
                if(vis[t]) continue;
                q.push(t),vis[t]=true;
            }
            else if(dis[t]==dis[x]+f[x][t]) sum[t]+=sum[x];
    }
}
int main()
{
    n=read(),m=read();
    for(int i=1;i<=n;i++)
     for(int j=1;j<=n;j++)
      f[i][j]=maxn;
    for(int i=1;i<=m;i++)
    {
        x=read(),y=read(),z=read();
        f[x][y]=min(f[x][y],z);
    }
    spfa(1);
    if(dis[n]==maxn) printf("No answer");
    else printf("%d %d",dis[n],sum[n]);
    return 0;
}

统计最缺乏路径的条数

婺源,是古徽州之一样有的,如今属江西省上饶市统,素有“八分割半山一样分割田,半分水道和公园”之称。

洛谷——P2196 挖地雷

题意:求于随机一个触及开始好开掘到的地雷的总和最多,求地雷总数与开的途径

题解:看数据范围n<=20所以我们可以跑n边spfa,枚举从各个一个沾开所能掘进到的极度多的地雷的数,如果手上路线的末梢挖到的地雷数最多,则印证这漫长道最精,如果我们美剧到的路径更漂亮,我们创新答案,更新路径

图片 30图片 31

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 300
using namespace std;
queue<int>q;
bool vis[N];
int n,m,x,y,e,tot,ans,maxn,sum;
int a[N],fa[N],pre[N],dis[N],head[N];
int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
struct Edge
{
    int to,dis,next;
}edge[N];
int add(int x,int y)
{
    tot++;
    edge[tot].to=y;
    edge[tot].next=head[x];
    head[x]=tot;
}
int spfa(int s)
{
    for(int i=1;i<=n;i++) dis[i]=0,vis[i]=false;
    q.push(s),vis[s]=true,dis[s]=a[s];
    while(!q.empty())
    {
        x=q.front();q.pop(),vis[x]=false;
        for(int i=head[x];i;i=edge[i].next)
        {
            int t=edge[i].to;
            if(dis[t]<=dis[x]+a[t])
            {
                dis[t]=dis[x]+a[t];
                fa[t]=x;
                if(vis[t]) continue;
                q.push(t),vis[t]=true;
            }
        }
    }
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++) a[i]=read();
    for(x=1;x<n;x++)
    {
        for(int y=x+1;y<=n;y++)
        {
            e=read();
            if(e) add(x,y);
        }
    }
    for(int s=1;s<=n;s++)
    {
        maxn=ans;
        memset(fa,-1,sizeof(fa));
        spfa(s);
        for(int i=1;i<=n;i++) 
         if(ans<dis[i]) e=i,ans=dis[i];
        if(ans==maxn) continue;
        sum=0;
        for(;e!=-1;e=fa[e])
         pre[++sum]=e;
    }
    for(int i=sum;i>=1;i--)
     printf("%d ",pre[i]);
    printf("\n%d",ans);
    return 0;
}

请最好丰富路由此及其长度

婺源是徽文化之策源地之一,素有“书乡”、“茶乡”之称,是全国知名的学识以及生态旅游目的地,被喻为“中国绝得意乡村”。

洛谷——P2296 寻找道路

题意:在祈求中搜索一条从起点至顶点的门道,该路线满足路径上的所有点的出边所对的触发都一直或间接与终点连过渡还路径最缺。

题解:题目中求我们找到的门路上的触及所并得点都得使跟结点直接或间接相连。因此我们建造反为无尽,然后bfs,搜索到巅峰不能到达的触及,我们就此好知晓,这些点所连接的点还不可知在咱们所要寻找的道被冒出,然后我们当飞一边是spfa求一下极差里程就是哼了

图片 32图片 33

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 200100
using namespace std;
queue<int>q;
bool vis[N],vist[N];
int n,m,s,e,x,y,tot,dis[N],head[N];
int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9') ch=getchar();
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
struct Edge
{
    int to,next;
}edge[N];
int add(int x,int y)
{
    tot++;
    edge[tot].to=y;
    edge[tot].next=head[x];
    head[x]=tot;
}
int spfa(int s)
{
    memset(vis,0,sizeof(vis));
    memset(dis,0x3f3f3f3f,sizeof(dis));
    dis[s]=0,vis[s]=true;q.push(s);
    while(!q.empty())
    {
        int x=q.front(); q.pop(); vis[x]=false;
        for(int i=head[x];i;i=edge[i].next)
        {
            int to=edge[i].to;
            if(dis[to]<=dis[x]+1||vist[to]) continue;
            dis[to]=dis[x]+1;
            if(vis[to]) continue;
            q.push(to);    
            vis[to]=true;
        }
    }
}
int bfs(int s)
{
    vis[s]=true;q.push(s);
    while(!q.empty())
    {
        int x=q.front(); q.pop();
        for(int i=head[x];i;i=edge[i].next)
        {
            int to=edge[i].to;
            if(!vis[to]) q.push(to),vis[to]=true;
        }
    }
}
int main()
{
    n=read(),m=read();
    for(int i=1;i<=m;i++)
     x=read(),y=read(),add(y,x);
    s=read(),e=read();
    bfs(e);
    for(int i=1;i<=n;i++)
     if(vis[i]==false)
      for(int j=head[i];j;j=edge[j].next)
        vist[edge[j].to]=true;
    for(int i=1;i<=n;i++)
     if(!vis[i]) vist[i]=true;
    spfa(e);
    if(dis[s]>=0x3f3f3f3f) printf("-1");
    else printf("%d",dis[s]);
    return 0;
}

搜寻有一致长条途径是路上之点所连接的点都与终极直接或者间接相连,并且使这长达路线最差

婺源主要分为东线、北线和西线三长达旅游路线。东线最为热点,沿途包括李坑、晓起、江岭相当于古老村,适合赏油菜花。北线的自然风光最好,有彩虹桥、思溪延村、理坑等色。西线开发比较晚,主要不外乎鸳鸯湖、文公山等于。

洛谷——P2176 [USACO14FEB]路障Roadblock

题意:在 M
条路的某个平等长达直达安放一叠稻草堆,使这条路的长度加倍,选择相同长总长干扰使得FJ
从下至牛棚的路长增加极其多,求最好特别增量

题解:我们领略更改最短路上的限度才见面使路径长度发生变化,因此我们先跑同合最短缺里程,然后记录最短缺路上的诸一样漫漫路径,然后暴力枚举每一样修路将其路径长度增为简单倍,然后以跑不过缺少路程,跑起之顶短路与第一软的极缺乏路程相减即为答案

有些总:1、对于这种转移同样条边,使s到t的门道增量最为特别,先跑不过缺里程,记录路径,只有改变路线上之触发才会使s到t的无限缺少路程长有变动,因此暴力枚举最短缺路上的诸一样漫漫边,看那条边改变后造成的熏陶最充分

2、改变图中一样长条边的消息,然后要最好缺里程等等的题材,一般是建筑反往度,跑少尽spfa,然后最缺少路程长为从1点届马上长长的路子s节点的门路+这漫长边的尺寸+终点到及时漫漫边的t节点的长短

图片 34图片 35

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 5100
using namespace std;
queue<int>q;
bool vis[N];
int n,m,x,y,z,tot=1,ans1,ans2,sum;
int fa[N],dis[N],head[N],node[N],num[N];
int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9') ch=getchar();
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f; 
}
struct Edge
{
    int to,dis,next,from;
}edge[N<<1];
int add(int x,int y,int z)
{
    tot++;
    edge[tot].to=y;
    edge[tot].dis=z;
    edge[tot].next=head[x];
    head[x]=tot;
}
int spfa(int s)
{
    memset(vis,0,sizeof(vis));
    memset(dis,0x3f3f3f3f,sizeof(dis));
    vis[s]=true,q.push(s),dis[s]=0;
    while(!q.empty())
    {
        int x=q.front();q.pop();vis[x]=false;
        for(int i=head[x];i;i=edge[i].next)
        {
            int to=edge[i].to;
            if(dis[to]>dis[x]+edge[i].dis)
            {
                dis[to]=dis[x]+edge[i].dis;
                fa[to]=x;num[to]=i;
                if(vis[to]) continue;
                q.push(to),vis[to]=true;
             }
        }
    }
}
int main()
{
    n=read(),m=read();
    for(int i=1;i<=m;i++)
    {
        x=read(),y=read(),z=read();
        add(x,y,z),add(y,x,z);
    }
    memset(fa,-1,sizeof(fa));
    spfa(1),ans1=dis[n];
    for(int i=n;i!=-1;i=fa[i])
      node[++sum]=num[i];
    for(int i=1;i<=sum;i++)
    {
        edge[node[i]].dis*=2;
        edge[node[i]^1].dis*=2;
        spfa(1);
        ans2=max(ans2,dis[n]);
        edge[node[i]].dis/=2;
        edge[node[i]^1].dis/=2;
    }
    printf("%d",ans2-ans1);
    return  0;
}

呼吁而哪条边的长改变如果s到t的途径长度增量最为充分

01/ 春季篇

洛谷——P1119 灾后重建

题意:给闹每个村庄重建道路完成的辰,第i独村落重建完成的时间t[i],可以认为是同时开始重建并于第t[i]圣重建完成,并且在同一天即可通车。若t[i]为0则印证地震未对斯地区造成破坏,一开始就是好通车。之后有Q只询问(x,
y, t),对于每个询问你一旦报在第t天,从村庄x到村庄y的最缺少路径长度为稍

题解:求最好短缺路径,无疑就是是极其短路的问题了,然后还拘留数据范围,看在多少范围就该想到这题要用Floyd。然后本题的t的单调递增的性为主题降低了老大怪之难度,这样咱们就非欲判定然后以拍卖了,在创新最短路的上咱们啊未用k
for循环到结尾更新最短里程了,因为他说t是单调的,我们直接一个while循环,从达成一样不善k不克创新的职一直开始,为什么?因为在就前面我们能够跟新的都与新了了,如果以创新一通就是一定给做了不管用功

图片 36图片 37

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 210
#define maxn 0x3f3f3f3f
using namespace std;
int n,m,x,y,z,k,T,Q,t[N],dis[N][N];
int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
int main()
{
    n=read(),m=read();k=1;
    for(int i=1;i<=n;i++) t[i]=read();
    for(int i=1;i<=n;i++)
     for(int j=1;j<=n;j++)
       dis[i][j]=maxn;
    for(int i=1;i<=m;i++)
    {
        x=read(),y=read(),z=read();
        dis[++x][++y]=dis[y][x]=z;
    }
    Q=read();
    while(Q--)
    {
        x=read(),y=read(),T=read();
        x++,y++;
        while(t[k]<=T&&k<=n)
        {
            for(int i=1;i<=n;i++)
             for(int j=1;j<=n;j++)
              dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
            k++;
        }
        if(dis[x][y]>=maxn||t[x]>T||t[y]>T) printf("-1\n");
        else printf("%d\n",dis[x][y]);
    }
    return 0;
}

View Code

婺源素以青春赏油菜花而名声鹊起,3月中下旬,是婺源油菜花集中盛开的季。漫山所在的菜花海,也是婺源最给欢迎之观光招牌。每当花季来临,被称呼“中国四老大花海”之一之婺源,都见面迎来大批的游人及拍爱好者。

2.spfa判负环

请一个接触至任何一个触及之太短缺路径,当这个图中出现负环或少数沾间尚未路子就是为无有由s点到t点的道路,如何判定是否是负环?跑spfa,如果一个点入队次数超过n次则印证出现负环

婺源赏油菜花的胜景,主要汇集在东线。站在梯田观景台,或是月亮湾畔,一望无际的金黄花海,尽收眼底。此外,庆源、晓起、官坑等村庄,也是欣赏油菜花海的绝佳之地。

洛谷—— P3385 【模板】负环

spfa判负环dfs版(dfs要较bfs的spfa判负环跑的赶快)

图片 38图片 39

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 200010
using namespace std;
bool vis[N],vist;
int n,m,t,x,y,z,tot,head[N],dis[N];
int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
struct Edge
{
    int to,dis,next;
}edge[N<<1];
int add(int x,int y,int z)
{
    tot++;
    edge[tot].to=y;
    edge[tot].dis=z;
    edge[tot].next=head[x];
    head[x]=tot;
}
int spfa(int x)
{
    vis[x]=true;
    for(int i=head[x];i;i=edge[i].next)
    {
        int t=edge[i].to;
        if(dis[t]>dis[x]+edge[i].dis)
        {
            dis[t]=dis[x]+edge[i].dis;
            if(vis[t]||vist)
            {
                vist=true;
                break;
            }
            spfa(t);
        }
    }
    vis[x]=false;
}
void begin()
{
    tot=vist=0;
    memset(dis,0,sizeof(dis));
    memset(head,0,sizeof(head));
    memset(vis,false,sizeof(vis));
}
int main()
{
    t=read();
    while(t--)
    {
        begin();
        n=read(),m=read();
        for(int i=1;i<=m;i++)
        {
            x=read(),y=read(),z=read();
            add(x,y,z);
            if(z>=0) add(y,x,z);
        } 
        for(int i=1;i<=n;i++)
        {
            spfa(i);
            if(vist) break;
        }
        if(vist) printf("YE5\n");
        else printf("N0\n");
    }
    return 0;
}

dfs的spfa判负环

【江岭】

codevs——2645 Spore

呢自星系1 到星系N 的极其小代价的路径的代价. 如果这么的门径不存,输出’No
such path’.                     spfa判负环裸题,bfs版    
线路未在就为出现了负环

图片 40图片 41

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 200010
#define maxn 9999999
using namespace std;
queue<int>q;
bool vis[N],vist;
int n,m,w,x,y,z,tot,head[N],dis[N],in[N];
int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
struct Edge
{
    int to,dis,next;
}edge[N<<1];
int add(int x,int y,int z)
{
    tot++;
    edge[tot].to=y;
    edge[tot].dis=z;
    edge[tot].next=head[x];
    head[x]=tot;
}
void begin()
{
    tot=vist=0;
    memset(in,0,sizeof(in));
    memset(dis,0,sizeof(dis));
    memset(vis,0,sizeof(vis));
    memset(head,0,sizeof(head));
}
int spfa(int s)
{
    while(!q.empty()) q.pop();
    for(int i=1;i<=n;i++) dis[i]=maxn,vis[i]=false;
    vis[s]=true,dis[s]=0,q.push(s);
    while(!q.empty())
    {
        x=q.front(),q.pop();vis[x]=false;
        for(int i=head[x];i;i=edge[i].next)
        {
            int t=edge[i].to;
            if(dis[t]>dis[x]+edge[i].dis)
            {
                dis[t]=dis[x]+edge[i].dis;
                if(!vis[t]) in[t]++,vis[t]=true,q.push(t);
                if(in[t]>n) return true;
            }
        }
    }
    return false;
}
int main()
{
     while(1)
    {
        begin();
        n=read(),m=read();
        if(n==0&&m==0) break;
        for(int i=1;i<=m;i++)
        {
            x=read(),y=read(),z=read(),w=read();
            add(x,y,z),add(y,x,w);
        }
        vist=spfa(1);
        if(vist||dis[n]==maxn) printf("No such path\n");
        else  printf("%d\n",dis[n]);
    }
    return 0;
}

bfs判负环,不要遗忘了初始化!

江岭放在婺源县极端东北,南临晓起,北接庆源。通常说之婺源油菜花,主要就是是当江岭邻近。这里的菜花田不以平中,而是以梯田上沿着山坡层层叠叠展开。每当油菜花开放时节,站在江岭之观景台上,可尽收眼底到婺源田园风光最美的一头。

洛谷——P2868 [USACO07DEC]游览奶牛Sightseeing Cows

题解:奶牛们于起点出发然后每当返起点,也就是说奶牛走过的门路为一个围,在奶牛走之之环中ans=所有的乐趣数/路上吃的富有的时刻。

咱们以方面的架子进行变形,可以抱路上吃的有着时间*ans=所有的乐趣数。——>路上吃的兼具时间*ans-所有的意趣数=0;

接下来我们以拓展第二瓜分答案,处理出ans,然后于各一个ans跑n个spfa,判断是否在负环,如果有负环就证实时方案免是最佳答案(存在负环条件:当前点入队次数超过n,当然这种情形是当我们之所以bfs的spfa时),让咱们为此dfs的spfa时,我们就此一个bool变量表示这个累起没有发生于看了,如果给看了,说明他出现了负环直接收循环。我们的ans还能产生再度特别的破,即当路上吃的享有的时*ans-所有的童趣数<0时咱们的ans不是眼下最优解继续创新最优解

留意:二划分了的标准化也r-l>0.000001,否则会爆long long

图片 42图片 43

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define N 51000
using namespace std;
bool vis[N];
int n,m,x,y,z,tot;
int c[N],num[N],head[N];
double ans,mid,l,r,w[N],dis[N];
struct Edge
{
    int to,dis,from,next;
}edge[N];
int add(int x,int y,int z)
{
    tot++;
    edge[tot].to=y;
    edge[tot].dis=z;
    edge[tot].next=head[x];
    head[x]=tot;
}
int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
int spfa(int x)
{
    vis[x]=true;
    for(int i=head[x];i;i=edge[i].next)
    {
        int t=edge[i].to;
        if(dis[t]>dis[x]+w[i])
        {
            dis[t]=dis[x]+w[i];
            if(vis[t]||spfa(t))
            {
                vis[x]=false;
                return true;
            }  
        }
    }
    vis[x]=false;
    return false;
}
int pd()
{
    for(int i=1;i<=n;i++)
        if(spfa(i)) return true;
    return false;
}
int main()
{
    n=read(),m=read();
    for(int i=1;i<=n;i++) c[i]=read();
    for(int i=1;i<=m;i++)
    {
        x=read(),y=read(),z=read();
        add(x,y,z);
    }
    l=0,r=100005;
    while(r-l>0.0000001)
    {
        mid=(l+r)/2;
        for(int i=1;i<=tot;i++)
        {
            int t=edge[i].to;
            w[i]=(double)mid*edge[i].dis-c[t];
        }
        if(pd())
        {
            ans=mid;
            l=mid;
        }
        else r=mid;
    }
    printf("%.2lf",ans);
    return 0;
}

二分+dfs判负环

 

漫山到处的菜花,从山头一直铺散到山沟下,谷底的水流围绕青山流淌,粉墙黛瓦的徽派民居,夹杂在同等切开金黄花海之间,再没比当下再度壮观之油菜花美景了。

         五、拓扑排序

一般是为此来呼吁给定n组顺序关系(名次,辈分,大小、、、),判断为有底音是否有抵触,求出符合条件的各个,如用要求来最为小之尽管用采取大根堆。拓扑排序还可以用来寻找一个图被之顶长链,也堪为此来搜寻打一个点出发的尽长链(经过一个触及的绝长链)不过只要优先事先处理一下

【庆源】

HDU——1285 确定比赛名次

被出n个名次关系,求出符合条件的排名顺序,输出字典序最小的答案

拓扑排序模板题,使用优先队列来如答案的字典序最小

图片 44图片 45

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 510
using namespace std;
priority_queue<int,vector<int>,greater<int> >q;
int n,m,x,y,tot,sum,in[N],ans[N],head[N];
int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
struct Edge
{
    int to,dis,next;
}edge[N];
int add(int x,int y)
{
    tot++;
    edge[tot].to=y;
    edge[tot].next=head[x];
    head[x]=tot;
}
int tpsort()
{
    for(int i=1;i<=n;i++)
     if(in[i]==0) q.push(i);
    while(!q.empty())
    {
        x=q.top(),q.pop(),sum++,ans[sum]=x;
        for(int i=head[x];i;i=edge[i].next)
        {
            int t=edge[i].to;
            in[t]--;
            if(in[t]==0) q.push(t);
        }
    }
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        sum=0,tot=0;
        memset(in,0,sizeof(in));
        memset(ans,0,sizeof(ans));
        memset(head,0,sizeof(head));
        memset(edge,0,sizeof(edge));
        for(int i=1;i<=m;i++)
         x=read(),y=read(),add(x,y),in[y]++;
        tpsort();
        for(int i=1;i<sum;i++)
         printf("%d ",ans[i]);
        printf("%d\n",ans[sum]);
    }
    return 0;
}

加以名次关系,求排列顺序

庆源位于婺源东线,紧挨江岭,又曰小桃源,有1300几近年的漫长历史。一长达宽约10米之汩汩小溪,穿村而过。每当油菜花起,古老朴素的庆源,被包围在平等片金黄花海中,处处是同样轴田园美景。

HDU——3342 Legal or Not

给出n对一一关系,询问所于有之涉嫌是否合法,即为未互相矛盾

题解:拓扑排序判环,当拓扑排序入队的触发之个数少于n时,即为出现了围

图片 46图片 47

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 510
using namespace std;
queue<int>q;
int n,m,x,y,tot,sum,in[N],head[N];
int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
struct Edge
{
    int to,next;
}edge[N];
int add(int x,int y)
{
    tot++;
    edge[tot].to=y;
    edge[tot].next=head[x];
    head[x]=tot;
}
bool tpsort()
{
    for(int i=1;i<=n;i++) 
     if(in[i]==0) q.push(i);
    while(!q.empty())
    {
        x=q.front(),q.pop(),sum++;
        for(int i=head[x];i;i=edge[i].next)
        {
            int t=edge[i].to;
            in[t]--;
            if(in[t]==0) q.push(t);
        }
    }    
    if(sum==n) return true;
    return false;
}
int main()
{
    while(1)
    {
        n=read(),m=read();
        if(n==0&&m==0) break;
        tot=0,sum=0;
        memset(in,0,sizeof(in));
        memset(head,0,sizeof(head));
        memset(edge,0,sizeof(edge));
        for(int i=1;i<=m;i++)
         x=read(),y=read(),add(x+1,y+1),in[y+1]++;
        if(tpsort()) printf("YES\n");
        else printf("NO\n");
    }
    return  0;
}

为出m对一一的干,询问给来底涉嫌是否矛盾

虽说没有江岭花海的气魄,但庆源自来一番聊家碧玉的色彩。村遭散落的油菜花田,小桥流水之原始图画,历经千不必要年,仍保存在平静质朴的乡味。

HDU——2647 Reward

老板娘要发作工钱,每个人都来一个渴求,他要于谁之薪资高,基准工资也888,求共最少用发小工资

题解:拓扑排序分层考虑,每一样层一栽工资,怎么判断是那么同样重合?对于基层我们是领略他以哪一样重叠的,然后我们各个一个入队的接触之层数一定是链接他的很在拔被之触发之层数+1

图片 48图片 49

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 20100
#define money 888
using namespace std;
queue<int>q;
long long anss;
int n,m,x,y,s,in[N],tot,sum,head[N],ans[N];
int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
struct Edge
{
    int from,to,next;
}edge[N];
int add(int x,int y)
{
    tot++;
    edge[tot].to=y;
    edge[tot].next=head[x];
    head[x]=tot;
}
void begin()
{
    s=0,sum=0,tot=0;anss=0;
    memset(in,0,sizeof(in));
    memset(ans,0,sizeof(ans));
    memset(head,0,sizeof(head));
    memset(edge,0,sizeof(edge));
}
int tpsort()
{
    for(int i=1;i<=n;i++)
     if(in[i]==0) q.push(i),ans[i]=0;
    while(!q.empty())
    {
        x=q.front();q.pop(),sum++;
        for(int i=head[x];i;i=edge[i].next)
        {
            int t=edge[i].to;
            in[t]--;
            if(in[t]==0) ans[t]=ans[x]+1,q.push(t);
        }
    }
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        begin();
        for(int i=1;i<=m;i++)
        {
            x=read(),y=read();
            add(y,x),in[x]++;
        }
        tpsort();
        if(sum!=n) printf("-1\n");
        else 
        {
            for(int i=1;i<=n;i++)
             anss+=money+ans[i];
            printf("%lld\n",anss);
        }       
    }
    return  0;
}

各一样交汇及的人头同样种工资,求最好少工资总数

 

【月亮湾】

洛谷—— P1347 排序

题意:给您一样多样形如A<B的干,并求而认清是否会冲这些关乎确定此数列的各个

题解:拓扑排序+模拟

图片 50图片 51

#include<queue>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define N 110
using namespace std;
int a,b,n,m,s,sum,tot,head[N],in[N],inn[N],p[N];
bool v,unpd,vis[N];
queue<int>q;
char ch;
int read()//在这里我用的读入优化 
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}
    return f*x;
}
struct Edge
{
    int from,to,next;
}edge[N];
int add(int x,int y)
{
    tot++;
    edge[tot].to=y;
    edge[tot].next=head[x];
    head[x]=tot;
}//和以前的拓扑排序过程一样,只是多加了几种情况 
int tp()
{
    unpd=false;    v=false; sum=0;//初始数值 
    for(int i=1;i<=26;i++)//开始找入读为一的点 
     {
         inn[i]=in[i];//由于我们要没输入一组后就对该序列进行判断,所以我们新设一个数组inn储存in中的各点入度的值,防止我们下一次在用时,该店的入度值已不是初始值 
         if(!inn[i]&&vis[i])//该点的入读为0并且我们输入过该值 
          {
              if(!v) v=true;//我们要判断有几个入读为0的点,由于如果有两个入读为0的点我们则无法判断他们的关系因为入读为0的点一定是小的,但这两个值得大小我们又无法判断 
              else unpd=true;//unpd用来判断无法判段的情况 
              q.push(i);
              p[++sum]=i;
           } 
      } 
    if(q.empty()) return 1;//如果q数组为空,就说明出现了环,则是存在矛盾的情况。 
    while(!q.empty())//单纯的拓扑排序,但我们要在里面多加一点东西:和前面判断入读为0的方法一样,如果删除一个点以后出现了两个入度为0的边,这样我们将无法判断这两个点的大小 
    {
        int x=q.front();v=false;q.pop();
        for(int i=head[x];i;i=edge[i].next)
        {
            inn[edge[i].to]--;
            if(!inn[edge[i].to])
            {
                q.push(edge[i].to);
                if(!v) v=true;
                else unpd=true;
                p[++sum]=edge[i].to;
            } 
        }
    }
    if(sum!=s) return 1;//说明出现了环。 
    if(unpd) return 2;
    return 0; 
}
int main()
{
    n=read(),m=read();
    for(int i=1;i<=m;i++)
    {
        cin>>ch,a=ch-64;if(!vis[a]) vis[a]=true,s++;//s是用来存我们输入的元素的个数,方便后面判断s值与sum值的关系(来判断是否为环) 
        cin>>ch;//这个在输入时其实我们也可以用一个数组来表示,在这里我们由于有一个<是没有用的,所以我们直接输入就好了 
        cin>>ch,b=ch-64;if(!vis[b]) vis[b]=true,s++;//vis用来表示该数有值 
        add(a,b);//在这里我们将我们输入的字符转化成了数字,方便后面进行操作 
        in[b]++;//储存入读 
        if(tp()==1) //在这里我们必须让他等于1,因为我们在tp函数中返回的是0,1,2 
        {
            printf("Inconsistency found after %d relations.",i);//存在矛盾 
            return 0;
        }
        if(sum==n&&!tp())//sum=n,说明该序列中所有的数都进行了排序,都能确定他们的位置 
        {
            printf("Sorted sequence determined after %d relations: ",i);
            for(int j=1;j<=n;j++) printf("%c",p[j]+64);//在最开始的时候我竟然让他输出p[i]+64.这告诉我们要注意我们循环使用的变量i,j 
            printf(".");
            return 0;
        }
    }
    printf("Sorted sequence cannot be determined.");//由于我们在tp函数中只有三种情况,除了前两种剩下的就是这一种了。 
    return 0;
}

让得一些关乎问是否能够经过吃出之干判断有因素的涉嫌,如果未可知问以第几步后涉及就是出现了抵触

月亮湾,是往李坑途中路过的一个粗岛屿,呈弯月相。清晨时节,是俯瞰月亮湾无限得意的时。只见晨雾笼于水面上,白墙、黑瓦、金花、绿水,在同等切开朦胧中愈发模糊,宛如一布置浑然天成的水墨画。

洛谷——P3119 [USACO15JAN]草鉴定Grass Cownoisseur

 法一:建反朝度,双向dfs找打1点能达标的卓绝长链,能够到达1点底不过长链,然后枚举需要反转之边,若能够创新最充分价值,则更新最要命价值。

图片 52图片 53

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 210000
using namespace std;
queue<int>q;
int n,m,x,y,s,tot,tot1,top,tim;
bool vis[N],vis1[N],vis2[N],vist1[N],vist2[N];
int xx[N],yy[N],in1[N],in2[N],head1[N],head2[N],dfn[N];
int low[N],sum[N],ans1[N],ans2[N],head[N],stack[N],belong[N];
int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
struct Edge
{
    int to,next;
}edge[N],edge1[N],edge2[N];
int add(int x,int y)
{
    tot++;
    edge[tot].to=y;
    edge[tot].next=head[x];
    head[x]=tot;
}
int add1(int x,int y)
{
    tot1++;
    edge1[tot1].to=y;
    edge1[tot1].next=head1[x];
    edge2[tot1].to=x;
    edge2[tot1].next=head2[y];
    head1[x]=head2[y]=tot1;
}
int tarjan(int x)
{
    dfn[x]=low[x]=++tim;
    stack[++top]=x,vis[x]=true;
    for(int i=head[x];i;i=edge[i].next)
    {
        int t=edge[i].to;
        if(vis[t]) low[x]=min(low[x],dfn[t]);
        else if(!dfn[t]) tarjan(t),low[x]=min(low[t],low[x]);
    }
    if(low[x]==dfn[x])
    {
        s++,sum[s]++,belong[x]=s;
        for(;stack[top]!=x;top--)
        {
            sum[s]++;
            vis[stack[top]]=false;
            belong[stack[top]]=s;
        }
        top--,vis[x]=false;
    }
}
int shink_point()
{
    for(int i=1;i<=n;i++)
     for(int j=head[i];j;j=edge[j].next)
     {
         int t=edge[j].to;
         if(belong[i]!=belong[t]) 
          add1(belong[i],belong[t]);
     }
}
int dfs1(int x)
{
    vis1[x]=true;
    for(int i=head1[x];i;i=edge1[i].next)
    {
        int t=edge1[i].to;
        if(ans1[t]<ans1[x]+sum[t])
         ans1[t]=ans1[x]+sum[t],dfs1(t);
    }
}
int dfs2(int x)
{
    vis2[x]=true;
    for(int i=head2[x];i;i=edge2[i].next)
    {
        int t=edge2[i].to;
        if(ans2[t]<ans2[x]+sum[t])
         ans2[t]=ans2[x]+sum[t],dfs2(t);
    }
}
int main()
{
     n=read(),m=read();
    for(int i=1;i<=m;i++)
     xx[i]=read(),yy[i]=read(),add(xx[i],yy[i]);
    for(int i=1;i<=n;i++)
     if(!dfn[i]) tarjan(i);
    shink_point();
    ans1[belong[1]]=ans2[belong[1]]=sum[belong[1]];
    dfs1(belong[1]);dfs2(belong[1]);
    int answer=2*sum[belong[1]];
    for(int i=1;i<=m;i++)
    {
        x=belong[yy[i]],y=belong[xx[i]];
        if(vis1[x]&&vis2[y])
         answer=max(answer,ans1[x]+ans2[y]);
    }
    printf("%d",answer-sum[belong[1]]);
    return 0;
}

求用同长达边反转以后图中之极致长链的长短

如法炮制二:拓扑排序求最好长链

曹假如直白开展拓扑排序的口舌,我们会发觉及一个题目:缩完点以后直接统计出来入度为零星底点并非是咱们所需要的触及1,我们如果飞不过长链的说话我们得由1点初始跑,也就是说我们的起点要是1,怎样就就或多或少??我们而形成起点是如出一辙底口舌我们亟须给1底入度为零星,从一些开始更新和外不住的接触。从新统计他们的入读,也就是说我们拿此也许出现环之希冀抽离成一粒树,这棵树之根须为1点。然后重新开展拓扑排序,找有最好长链。

图片 54图片 55

#include<queue>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 210000
using namespace std;
int n,m,x,y,s,tot,tat,top,tim;
bool vis[N],vis1[N],vis2[N];
int xx[N],yy[N],in1[N],in2[N],head1[N],head2[N],dfn[N];
int low[N],sum[N],ans1[N],ans2[N],head[N],stack[N],belong[N];
int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
struct Edge
{
    int to,from,next;
}edge[N],edge1[N],edge2[N];
int add(int x,int y)
{
    tot++;
    edge[tot].to=y;
    edge[tot].next=head[x];
    head[x]=tot;
}
int add1(int x,int y)
{
    tat++;
    edge1[tat].to=y;
    edge1[tat].next=head1[x];
    edge2[tat].to=x;
    edge2[tat].next=head2[y];
    head1[x]=head2[y]=tat;
}
int tarjan(int now)
{
    dfn[now]=low[now]=++tim;
    vis[now]=true;stack[++top]=now;
    for(int i=head[now];i;i=edge[i].next)
    {
        int t=edge[i].to;
        if(vis[t]) low[now]=min(dfn[t],low[now]);
        else if(!dfn[t]) tarjan(t),low[now]=min(low[t],low[now]);
    }
    if(low[now]==dfn[now])
    {
        s++,belong[now]=s,sum[s]++;
        for(;stack[top]!=now;top--)
          belong[stack[top]]=s,sum[s]++,vis[stack[top]]=false;
        vis[now]=false;top--;    
    }
}
int shink_point()
{
    for(int i=1;i<=m;i++)
     for(int j=head[i];j;j=edge[j].next)
      if(belong[i]!=belong[edge[j].to])
          add1(belong[i],belong[edge[j].to]);  
}
int dfs1(int s)
{
    for(int i=head1[s];i;i=edge1[i].next)
    {
        int t=edge1[i].to;
        if(!in1[t]) dfs1(t);
        in1[t]++;
    }
}
int dfs2(int s)
{
    for(int i=head2[s];i;i=edge2[i].next)
    {
        int t=edge2[i].to;
        if(!in2[t]) dfs2(t);
        in2[t]++;
    }
}
int tpsort(int *in,Edge *edge,int *head,bool *vis,int *ans)
{
    queue<int>q;
    q.push(belong[1]);
    while(!q.empty())
    {
        int x=q.front();q.pop();vis[x]=true;
        for(int i=head[x];i;i=edge[i].next)
        {
            int t=edge[i].to;
            in[t]--;
            if(!in[t]) q.push(t);
            ans[t]=max(ans[t],ans[x]+sum[t]);
        }
    }
}
int main()
{
    n=read(),m=read();
    int answer=0;
    for(int i=1;i<=m;i++)
     xx[i]=read(),yy[i]=read(),add(xx[i],yy[i]);
    for(int i=1;i<=n;i++)
     if(!dfn[i]) tarjan(i);
    shink_point();
    dfs1(belong[1]),dfs2(belong[1]);
    ans1[belong[1]]=ans2[belong[1]]=sum[belong[1]];
    tpsort(in1,edge1,head1,vis1,ans1);
    tpsort(in2,edge2,head2,vis2,ans2);
    answer=2*sum[belong[1]];
    for(int i=1;i<=m;i++)
    {
        x=belong[yy[i]],y=belong[xx[i]];
        if(vis1[x]&&vis2[y])
         answer=max(answer,ans1[x]+ans2[y]);
    }
    printf("%d",answer-sum[belong[1]]);
    return 0;
}

拓扑排序求最好长链

观赏与照相月亮湾之最佳角度,是当相邻山上的观景台,可起边上一长小路上山。油菜花开放时,从观景台俯瞰,整个月湾染成一切开金黄色,异常惊艳震撼。

          六、二分图

绝小顶点覆盖是因太少的顶点数使得二细分图被之各条边都至少与其间一个点相关联,二分图的太小顶点覆盖数=二分开图的极其充分匹配数;

最小路径/点覆盖是依赖用尽量少的莫交路径覆盖二分叉图被之兼具终端。二细分图的无限小路径覆盖数=|V|-二区划图的最好要命匹配日数    

不过老独立集(指寻找一个点集,使得中擅自两碰在祈求被任针对应边)=|V|-二分图的尽特别匹配数

02/ 秋季篇

洛谷——P3386 【模板】二细分图匹配

图片 56图片 57

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 1010
using namespace std;
bool vis[N];
int n,m,e,x,y,ans,girl[N],map[N][N];
int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
int find(int x)
{
    for(int i=1;i<=m;i++)
     if(map[x][i]&&!vis[i])
     {
         vis[i]=true;
         if(find(girl[i])||!girl[i])
         {
             girl[i]=x;
             return true;
         }
     }
     return false;
}
int main()
{
    n=read(),m=read(),e=read();
    for(int i=1;i<=e;i++)
     x=read(),y=read(),map[x][y]=1;
    for(int i=1;i<=n;i++)
    {
        memset(vis,0,sizeof(vis));
        if(find(i)) ans++;
    }
    printf("%d",ans);
    return 0;
}

次私分图太要命匹配

除去油菜花,婺源也是赏秋的超级选择。徽式建筑映衬下的红叶彩林,仿佛从翻了颜色桶,到处是暖和的情调。高大斑斓的红枫下,堆满了金色的柴垛。粉墙黛瓦的屋顶,晒起了火红的辣椒。蓝天碧水、白墙黑瓦、红枫彩林,交相辉映,犹如一帧意境深远的彩笔画。

poj——3041    Asteroids

11月中下旬,是通往婺源赏红叶、观晨雾的极端美好时。石城、长溪相当于地,均是欣赏秋景的好去处。在篁岭,还可感受当地“晒秋”的乡规民约。家家户户的屋顶上,到处晾晒在吉祥番椒、稻谷等色彩鲜艳的农作物,绘就发出一致幅多彩的“晒秋”美景。

题意:给您一个N*N的矩阵,有有格子里有小行星,现在你生出一部分威力非常怪之炮弹,每一样次于发都能够灭掉矩阵中一行要同排列的小行星,求最好少发次数

题解:行列匹配,对于这种每次只能消灭一行要同一排列的操作,我们得以将各一行看成一个凑,将诸一样排列作一个汇,然后跑二私分图匹配,题目中要求最少多少步可将稍微点儿全部消灭,就是被求最好少用多少条边将拥有的触及通掩,也尽管是无限小点覆盖问题=最可怜匹配数,然后就是单模板题了

 

图片 58图片 59

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 1010
using namespace std;
bool vis[N];
int n,m,e,x,y,ans,girl[N],map[N][N];
int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
int find(int x)
{
    for(int i=1;i<=n;i++)
     if(map[x][i]&&!vis[i])
     {
         vis[i]=true;
         if(find(girl[i])||!girl[i])
         {
             girl[i]=x;
             return 1;
         }
     }
    return 0;
}
int main()
{
    n=read(),m=read();
    for(int i=1;i<=m;i++)
     x=read(),y=read(),map[x][y]=1;
    for(int i=1;i<=n;i++)
    {
        memset(vis,0,sizeof(vis));
        if(find(i)) ans++;
    }
    printf("%d",ans);
    return 0;
 } 

行匹配:每次只能消灭一行要一列,问尽少小步可以。。全部消灭

 

【篁岭】

poj —— 1274 The Perfect Stall

题意:给闹一部分爱关系,一条牛只会选则一个摊,牛只出在投机喜爱的摊点上才能够产奶,问尽多产奶总数

小总:对于好种(或者一个接触得选外一个触及)的题材,求最好多会满足的总人口(对数)一般是亚瓜分图要最好特别匹配裸题

图片 60图片 61

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 1010
using namespace std;
bool vis[N];
int n,m,k,x,y,ans,girl[N],map[N][N];
int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
int find(int x)
{
    for(int i=1;i<=m;i++)
     if(map[x][i]&&!vis[i])
     {
         vis[i]=true;
         if(find(girl[i])||girl[i]==-1)
         {
             girl[i]=x;
             return 1;
         }
     }
     return 0;
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        ans=0;
        memset(map,0,sizeof(map));
        memset(girl,-1,sizeof(girl));
        for(int i=1;i<=n;i++)
        {
            k=read();
            while(k--) x=read(),map[i][x]=1;
        }
        for(int i=1;i<=n;i++)
        {
            memset(vis,0,sizeof(vis));
            if(find(i)) ans++;
        }
        printf("%d\n",ans);
    }
    return 0;
 } 

最好多满足的人口

篁岭,地处婺源东线山区,因村被“地任三尺平”,村落依山而修筑,民居呈阶梯状扇型分布。这种先天性之自条件局限,激发了篁岭先民的设想和创造力。

 HDU——1150 Machine Schedule

题意:给出片雅机器A、B,机器A上出n种模式,机器B上发m种模式,现有k个需要周转的职责,每个任务产生相应的运行模式,(i, x, y)表示i任务对应的A B机器上的运作模式为x,y. 开始之办事模式都是0.各国台机器上之任务可随自由顺序执行,但是各个台机器每转换一次于模式需重开一坏。求机还开的至少次数

题解:我们对每一个职责连边,然后我们现若是成功任务而我们设讲求机器还开的次数最少,那么也即是说咱俩要为此到最少的触及把具有的边连起来,这样尽管转发成为了最为小点覆盖的裸题了                
最小点覆盖等最要命匹配数

图片 62图片 63

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 1010
using namespace std;
bool vis[N];
int n,m,k,x,y,z,ans,girl[N],map[N][N];
int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
int find(int x)
{
    for(int i=1;i<=m;i++)
    {
        if(!vis[i]&&map[x][i])
        {
            vis[i]=true;
            if(girl[i]==-1||find(girl[i])) {girl[i]=x; return 1;}
        }
    }
    return 0;
}
int main()
{
    while(1)
    {
        n=read();if(n==0) break;
        m=read(),k=read();ans=0;
        memset(map,0,sizeof(map));
        memset(girl,-1,sizeof(girl));
        for(int i=1;i<=k;i++)
        {
            z=read(),x=read(),y=read();
            map[x][y]=1;
        }
        for(int i=1;i<=n;i++)
        {
            memset(vis,0,sizeof(vis));
            if(find(i)) ans++;
        }
        printf("%d\n",ans);
    }
    return 0;
}

极致小点覆盖

年年夏季秋交替,篁岭房前屋后,便成为了竹晒匾的社会风气。长长木架托起圆圆的晒匾,春晒蕨菜、水笋;夏晒南瓜、豆角;秋晒稻谷、辣椒。五颜六色的丰收作物,映衬着徽派建筑之粉墙黛瓦,绘就有了凡难得的“晒秋”民俗美景。

HDU——2768 Cat vs. Dog

题意:喜欢猫的得不喜欢狗,喜欢狗的早晚不喜欢猫,我们若选择则养猫还是养狗,使饱的食指无限多

题解: 我们用喜欢猫的和喜欢狗的划分成稀个集,然后将马上半单聚众中有矛盾的点连边,构图,跑二分开图匹配,答案和为极端深独立集,最酷独立集=总点数-最酷匹配数

稍稍总:给出n对爱关系,喜欢A的未喜欢B,喜欢B的未喜欢A,我们摘一个总人口,问尽多克是微个人满足,这个时候咱们将喜欢A的作为一个几哪,喜欢B的当一个聚,然后以即刻点儿只集聚中是抵触的连边,跑不过可怜独立集

【石城】

HDU——2444 The Accomodation of Students

题目:一些生中间是情侣干(关系匪可知传递),问是否以学生分为两堆积使得同一堆的生中不是有情人。如果非得以出口“No”,可以的言辞输出最多可分出几针对性小盆友。

题解:先二分叉图染色判断该是否是第二细分图,然后于飞不过充分匹配

图片 64图片 65

#include<queue>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 510
using namespace std;
bool flag,vis[N];
int n,m,x,y,tot,ans,col[N],girl[N],head[N],map[N][N];
queue<int>q;
struct Edge
{
    int from,to,next;
}edge[N*N];
int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
int add(int x,int y)
{
    tot++;
    edge[tot].to=y;
    edge[tot].next=head[x];
    head[x]=tot;
}
int find(int x)
{
    for(int i=1;i<=n;i++)
    {
        if(!vis[i]&&map[x][i])
        {
            vis[i]=true;
            if(girl[i]==-1||find(girl[i])){girl[i]=x; return 1;}
        }
    }
    return 0;
}
int color(int s)
{
    queue<int>q;
    q.push(s); col[s]=0;
    while(!q.empty())
    {
        int x=q.front();
        for(int i=head[x];i;i=edge[i].next)
        {
            int t=edge[i].to;
            if(col[t]!=-1){if(col[t]==col[x]) {flag=true; return 1;}}
            else
            {
                col[t]=col[x]^1;
                q.push(t);
            }
        }
        q.pop();
    }
    return 0;
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        ans=0;flag=false;tot=0;
        memset(map,0,sizeof(map));
        memset(col,-1,sizeof(col));
        memset(edge,0,sizeof(edge));
        memset(head,0,sizeof(head));
        for(int i=1;i<=m;i++)
        {
            x=read(),y=read();
            map[x][y]=1;
            add(x,y),add(y,x);
        }
        for(int i=1;i<=n;i++)
         if(col[i]==-1)
         {
             if(color(i)) break;
          } 
        if(flag) {printf("No\n"); continue;}
        memset(girl,-1,sizeof(girl));
        for(int i=1;i<=n;i++)
        {
            memset(vis,0,sizeof(vis));
            if(find(i)) ans++;
        }
        printf("%d\n",ans);
    }
    return 0;
}

老二区划图染色+最要命匹配数

婺源石城,坐落在婺源县西北,古枫齐聚,奇树成群。百余蔸历史悠久的枫,树大全以35米以上。每届深秋,大片的枫树林一切片火红,在白墙黑瓦之徽派建筑映衬下,构成了平轴精美绮丽的画卷。

洛谷——P2756 飞行员配对方案问题

KM算法

每年11月-12月上旬,是婺源石城秋色最美的时令。徜徉在花团锦簇的伟人枫林中,秋意浓浓。火红的秋叶、朦胧的晨雾、袅袅的炊烟,让这于山体中沉寂已久的古旧村,成为了众人无限爱之秋色摄影之地。

         六、LCA

【长溪】

洛谷——P3379 【模板】最近国有祖先(LCA)

图片 66图片 67

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 501000
using namespace std;
int n,m,tot,x,y,root;
int fa[N],top[N],size[N],deep[N],head[N];
int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
struct Edge
{
    int to,next;
}edge[N<<1];
int add(int x,int y)
{
    tot++;
    edge[tot].to=y;
    edge[tot].next=head[x];
    head[x]=tot;
}
int dfs(int x)
{
    size[x]=1;
    deep[x]=deep[fa[x]]+1;
    for(int i=head[x];i;i=edge[i].next)
    {
        int t=edge[i].to;
        if(fa[x]==t) continue;
        fa[t]=x,dfs(t);
        size[x]+=size[t];
    }
}
int dfs1(int x)
{
    int t=0;
    if(!top[x]) top[x]=x;
    for(int i=head[x];i;i=edge[i].next)
    {
        int to=edge[i].to;
        if(fa[x]!=to&&size[t]<size[to]) t=to;
    }
    if(t) top[t]=top[x],dfs1(t);
    for(int i=head[x];i;i=edge[i].next)
    {
        int to=edge[i].to;
        if(fa[x]!=to&&to!=t) dfs1(to);
    }
}
int LCA(int x,int y)
{
    for(;top[x]!=top[y];x=fa[top[x]])
     if(deep[top[x]]<deep[top[y]])
      swap(x,y);
    if(deep[x]>deep[y]) swap(x,y);
    return x;
}
int main()
{
    n=read(),m=read(),root=read();
    for(int i=1;i<n;i++)
     x=read(),y=read(),add(x,y),add(y,x);
    dfs(root),dfs1(root);
    for(int i=1;i<=m;i++)
    {
        x=read(),y=read();
        printf("%d\n",LCA(x,y));
    }
    return 0;
}

LCA模板

 

藏于婺源深山中之长溪村,历来是婺源高山茶的著名产地。春天来品茗香茶,体验亲手采茶的意趣。而至了深秋,高大的瑞枫与白墙黑瓦掩映,吸引了诸多摄影爱好者。

长溪村职比较偏僻,人烟稀少。由于交通不便,这里仍然保留着旧质朴的山乡气息。每年11月中下旬及12月初,长溪村内外大片古老的枫树林,一片火红,在天发与日落时分前来赏拍照,美不胜收。

正文为原创,欢迎分享,转载请注明作者和出处。部分图片源于网络,版权归原作者有。如发生侵权,请联系我们去。

微信公众号:旅游知识坊

END