poj 1236 Kosaraju 强连通

题意:电脑可以向自己list的电脑传输文件,而且是秒传(我们学校的网络能这么好,就帅死了),一、问最少向几个电脑投文件,二、连接最少的边使图成为强连通图

解法:缩点,一个强连通分量为一个点(抽象的),因为一个连通分量内文件是可以互传的,相当于一个点(是不是很像并查集),扫描所有的边,统计各个分量间的出度入度关系。

       问题一:入度为零的分量个数

       问题二:max(入度为零的个数,出度为零的个数),道理应该挺简单的吧。

/*
----------------------------------

   Love is more than a word.
   It says so much.
   When I see these four letters,
   I almost feel your touch.
   This is only happened since
   I fell in love with you.
   Why this word does this,
   I haven't got a clue.

                   To My Goddess
                          CY
----------------------------------
*/

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<vector>
#include<cmath>
#include<stdlib.h>
#include<iomanip>
#include<list>
#include<deque>
#include<map>
#include <stdio.h>
#include <queue>

#define maxn 10000+5
#define maxm 155
#define ull unsigned long long
 #define ll long long
#define reP(i,n) for(i=1;i<=n;i++)
 #define REP(i,a,b) for(i=a;i<=b;i++)
  #define rep(i,n) for(i=0;i<n;i++)

#define cle(a) memset(a,0,sizeof(a))
 #define clehead(a) rep(i,maxn)a[i]=-1

/*
  The time of story :
  **  while(1)
    {
         once upon a time,
         there was a mountain,
         on top of which there was a temple,
         in which there was an old monk and a little monk.
         Old monk was telling stories inside the temple.
         What was he talking about?
  **  }

   ÎûÎû
   (*^__^*)
*/

#define sci(a) scanf("%d",&a)
 #define scd(a) scanf("%lf",&a)
  #define pri(a) printf("%d",a)
   #define prie(a) printf("%d\n",a)
    #define prd(a)  printf("%lf",a)
     #define prde(a) printf("%lf\n",a)
      #define pre printf("\n")

#define LL(x) x<<1
 #define RR(x) x<<|1

#define pb push_back
#define mod 90001
#define PI 3.141592657

const ull INF = 1LL << 61;
const int inf =   int(1e5)+10;
const double eps=1e-5;

using namespace std;

struct node
{
   int v;
   int next;
}edge1[maxn],edge2[maxn];

int head1[maxn],head2[maxn];
int used1[maxn],used2[maxn];
int Scc[maxn];//记录每个点所属的集合
int num[maxn];//记录第一次搜索的遍历顺序
int cnt1,cnt2;
int n;
int sig;

struct EDGE{//储存边的信息
   int x,y;
}val[maxn];

void init()
{
    cnt1=cnt2=1;
    for(int i=1;i<=n;i++)head1[i]=head2[i]=-1;
    cle(used1);
    cle(used2);
    cle(num);
}
void add(int x,int y)
{
    edge1[cnt1].v=y,edge1[cnt1].next=head1[x],head1[x]=cnt1++;
    edge2[cnt2].v=x,edge2[cnt2].next=head2[y],head2[y]=cnt2++;
}
void dfs1(int x,int &sig)
{
    used1[x]=1;
    for(int i=head1[x];i!=-1;i=edge1[i].next){
        if(used1[edge1[i].v]==0)dfs1(edge1[i].v,sig);
    }
    num[sig++]=x;
}
void dfs2(int x,int sig)
{
    used2[x]=1;
    Scc[x]=sig;
    for(int i=head2[x];i!=-1;i=edge2[i].next)
    {
        if(used2[edge2[i].v]==0)
        {
            dfs2(edge2[i].v,sig);
        }
    }
}
int main()
{
    freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    while(cin>>n)
    {
        init();
        int i;int ip=1;
        reP(i,n)
        {
            int temp;
            while(cin>>temp&&temp)
            {
                val[ip].x=i,val[ip++].y=temp;
                add(i,temp);
            }
        }
        sig=1;
        reP(i,n){
            if(used1[i]==0)
            {
                dfs1(i,sig);
            }
        }
        sig=1;
        for(i=n;i>0;i--)
        {
            if(used2[num[i]]==0)
            {
                dfs2(num[i],sig++);
            }
        }

        int in[maxn];
        int out[maxn];
        cle(in);
        cle(out);
        for(i=1;i<ip;i++)
        {
            if(Scc[val[i].x]!=Scc[val[i].y])
            {
                out[Scc[val[i].x]]++;
                in[Scc[val[i].y]]++;
            }
        }
        int ans1=0;
        int ans2=0;
        for(i=1;i<sig;i++)
        {
            if(in[i]==0)ans1++;
            if(out[i]==0)ans2++;
        }
        //cout<<sig<<endl;
        if(sig==2)
        {
            cout<<1<<endl;
            cout<<0<<endl;
        }
        else
        {
            cout<<ans1<<endl;
            cout<<max(ans1,ans2)<<endl;
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值