5588葡京线路洛谷—— P2812 校园网络

7. 通信线路

★★   输入文件:mcst.in   输出文件:mcst.out   简单对比
时光范围:1.5 s   内存限制:128 MB

题目讲述

倘若要当n个城市次建立通信联络网,则连通n个城市仅待n-1漫漫路。这时,
如何在至少经费之前提下成立此通信网。在列半单市次都得安装—条线,相应地且使交一定的经济代价。n个城市内,最多或设置n(n-
1)/2漫漫线,那么,如何在这些恐怕的路线受到选取n-1条,以使总的消耗最少为?

 

【输入格式】

输入文件发出好多实施
率先实践,一个整数n,表示共有n个城市
第2–n+1行,每行n个数,分别代表该城市和任何城市次路线的开销,如果都中不克起通信则用-1意味着

 

【输出格式】

一行,1单整数,表示最少总用

 

【输入输出样例】

 

输入文件

 


-1 5 -1 -1 -1 -1 
5 -1 50 -1 -1 10
-1 50 -1 20 10 -1
-1 -1 20 -1 60 30
-1 -1 10 60 -1 100
-1 10 -1 30 100 -1

 

出口文件

 

75

 

【数据规模】

 

对于40%的数据,保证有n<100: 
对于60%的数据,保证有n<256; 
对所有之多寡,保证发生n<=1501。

 

 

习一下尽小生成树

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 5000000
using namespace std;
int n,x,y,z,tot,ans,sum,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,z;
}edge[N];
int cmp(Edge a,Edge b)
{
    return a.z<b.z;
}
int find(int x)
{
    if(fa[x]==x) return x;
    fa[x]=find(fa[x]);
    return fa[x];
}
int main()
{
    freopen("mcst.in","r",stdin);
    freopen("mcst.out","w",stdout);
    n=read();
    for(int i=1;i<=n;i++)
     for(int j=1;j<=n;j++)
    {
        z=read();
        if(z==-1) continue;
        tot++;
        edge[tot].x=i;
        edge[tot].y=j;
        edge[tot].z=z;
    }
    sort(edge+1,edge+1+tot,cmp);
    for(int i=1;i<=n;i++) fa[i]=i;
    for(int i=1;i<=tot;i++)
    {
        x=edge[i].x,y=edge[i].y;
        int fx=find(x),fy=find(y);
        if(fx==fy) continue;
        fa[fx]=fy;ans+=edge[i].z;
        sum++;
        if(sum==n-1) break;
    }
    printf("%d",ans);
    return 0;
}

 

 P2812 校园网络

问题背景

浙江省的几乎所OI强校的神犇发明了扳平栽人工智能,可以AC任何问题,所以她们控制成立一个大网来共享斯软件。但是由于她们头脑累了多招浑身无力身体为♂掏♂空,他们来寻找你帮助他们。

问题叙述

共有n所学校(n<=10000)已掌握他们实现规划好之网络并m条线路,为了确保高速,网络是止为的。现在要您告诉他们足足选几所院校当共享软件的母机母鸡,能要各国所学校都好为此上。再告知她们足足要填补加几长达路线会如任意一所学当母机母鸡犹足以使别的校采取及软件。

输入输出格式

输入格式:

 

率先推行一个整数n。

接下n行每行有好多单整数,用空格空格隔开。

第i-1执之非零整数x,表示从i到x有相同长路线。以0作为了标志。

 

输出格式:

 

先是推行一个平头表示问题1之答案。

其次执行回答问题2.

 

输入输出样例

输入样例#1:

5
2 0
4 0
5 0
1 0
0

输出样例#1:

2
2

说明

POJ原题。数据扩大了100倍。

 

tarjan求强连通分量水题

请来强连通分量以后,我们知晓入度为零星的点就算是管音讯来之接触。

强连通分量满足该强连通分量中无入度为零星的触及及出度为零星之触发,那么我们要长的限的条数就是max(入度为零星之触及之个数,出度为零星底触发的个数)

代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define N 100000
using namespace std;
bool vis[N];
int n,x,top,tim,tot,sum,ans,ans1,ans2;
int in[N],out[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 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 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 t=stack[top];
            belong[t]=sum,vis[t]=false;
        }
        vis[now]=false; top--;
    }
}
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)
        {
            x=read();
            if(x==0) break;
            add(i,x);
        }
    }  
    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) ans1++;
        if(out[i]==0) ans2++;
     } 
    ans=max(ans1,ans2);
    printf("%d\n%d\n",ans1,ans);
    return 0;
}