Network of Schools(tarjan缩点+统计度数)

http://poj.org/problem?id=1236


思路:第一问的话其实还有其他的方法可做。那道题叫做刻录光盘,通过并查集和统计度数来完成。P2835 刻录光盘(并查集建单向边)

这道题的思路:首先tarjan缩点。缩点缩完了后看新图之间有多少个入度为0的点,这就是最后要给的作为起始的点。

对于第二问,缩点完后考虑几种情况会发现:

1-->2<----3

       ^

       |

       4

 2<----1------>3

           |

           V

           4

分别要在入度为0和出度为0中选一个最大的。

#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<stack>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=1e2+100;
typedef long long LL;
vector<LL>g[maxn];
stack<LL>s;
LL dfn[maxn],low[maxn],times=0,cnt=0,in[maxn],out[maxn];
bool inq[maxn];
LL col[maxn];///缩点
void tarjan(LL x)
{
    dfn[x]=low[x]=++times;
    s.push(x);inq[x]=true;
    for(LL i=0;i<g[x].size();i++)
    {
        LL to=g[x][i];
        if(!dfn[to])
        {
            tarjan(to);
            low[x]=min(low[x],low[to]);
        }
        else if(inq[to])
        {
            low[x]=min(low[x],dfn[to]);
        }
    }
    if(dfn[x]==low[x])
    {
        cnt++;
        LL y;
        do
        {
            y=s.top();
            inq[y]=false;
            col[y]=cnt;
            s.pop();
        }while(y!=x);
        return;
    }
}
int main(void)
{
    LL n;cin>>n;
    for(LL i=1;i<=n;i++)
    {
        LL to;
        while(cin>>to&&to!=0)
        {
            g[i].push_back(to);
        }
    }
    for(LL i=1;i<=n;i++)
    {
        if(!dfn[i]) tarjan(i);
    }
    if(cnt==1) cout<<1<<endl<<0<<endl;
    else
    {
        for(LL i=1;i<=n;i++)
        {
            for(LL j=0;j<g[i].size();j++)
            {
                if(col[i]!=col[g[i][j]]) in[col[g[i][j]]]++,out[col[i]]++;
            }
        }
        LL ans1=0;LL ans2=0;
        for(LL i=1;i<=cnt;i++)
        {
            if(in[i]==0) ans1++;
            if(out[i]==0) ans2++;
        }
        cout<<ans1<<endl<<max(ans1,ans2)<<endl;
    }
}

    

猜你喜欢

转载自blog.csdn.net/zstuyyyyccccbbbb/article/details/108885156