【算法提高——第三讲(二)】图论

来自:算法提高课

第三讲(二) 图论

3.7 负环

3.7.1 904. 虫洞

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=510,M=6010;

int F,n,m,W;
int h[N],e[M],w[M],ne[M],idx;
int dis[N];
bool st[N];
int cnt[N];
void add(int a,int b,int c)
{
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}

bool spfa()
{
    memset(cnt,0,sizeof cnt);
    memset(dis,0x3f,sizeof dis);
    dis[1]=0;
    queue<int> q;
    for(int i=1;i<=n;i++)
    {
        q.push(i);
        st[i]=true;
    }

    while(q.size())
    {
        int t=q.front();
        q.pop();
        st[t]=false;

        for(int i=h[t];i!=-1;i=ne[i])
        {
            int j=e[i];
            if(dis[j]>dis[t]+w[i])
            {
                dis[j]=dis[t]+w[i];
                cnt[j]=cnt[t]+1;
                if(cnt[j]>=n) return true;
                if(!st[j])
                {
                    q.push(j);
                    st[j]=true;
                }
            }
        }
    }
    return false;
}
int main()
{
    ios::sync_with_stdio(0);

    cin>>F;
    while(F--)
    {
        memset(h,-1,sizeof h);
        idx=0;
        cin>>n>>m>>W;
        for(int i=0;i<m;i++)
        {
            int a,b,c;
            cin>>a>>b>>c;
            add(a,b,c),add(b,a,c);
        }
        for(int i=0;i<W;i++)
        {
            int a,b,c;
            cin>>a>>b>>c;
            add(a,b,-c);
        }

        if(spfa()) cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
    }
    return 0;
}

3.7.2 361. 观光奶牛

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1010,M=5010;

int n,m;
int wf[N];
double dis[N];
bool st[N];
int cnt[N];
int h[N],e[M],w[M],ne[M],idx;
void add(int a,int b,int c)
{
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}

bool check(double mid)
{
    memset(dis,0,sizeof dis);
    memset(st,0,sizeof st);
    memset(cnt,0,sizeof cnt);

    queue<int> q;
    for(int i=1;i<=n;i++)
    {
        q.push(i);
        st[i]=true;
    }

    while(q.size())
    {
        int t=q.front();
        q.pop();
        st[t]=false;

        for(int i=h[t];i!=-1;i=ne[i])
        {
            int j=e[i];
            if(dis[j]<dis[t]+wf[t]-mid*w[i])
            {
                dis[j]=dis[t]+wf[t]-mid*w[i];
                cnt[j]=cnt[t]+1;
                if(cnt[j]>=n) return true;
                if(!st[j])
                {
                    q.push(j);
                    st[j]=true;
                }
            }
        }
    }
    return false;
}
int main()
{

    memset(h,-1,sizeof h);

    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>wf[i];

    for(int i=0;i<m;i++)
    {
        int a,b,c;
        cin>>a>>b>>c;
        add(a,b,c);
    }

    double l=0,r=1010;
    while(r-l>1e-4)
    {
        double mid=(l+r)/2;
        if(check(mid)) l=mid;
        else r=mid;
    }

    printf("%.2f",r);
    return 0;
}

3.7.3 1165. 单词环

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=700,M=100010;

int n;
double dis[N];
bool st[N];
int cnt[N];
int h[N],e[M],w[M],ne[M],idx;
void add(int a,int b,int c)
{
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}

bool check(double mid)
{
    memset(dis,0,sizeof dis);
    memset(st,0,sizeof st);
    memset(cnt,0,sizeof cnt);

    queue<int> q;
    for(int i=0;i<n;i++)
    {
        q.push(i);
        st[i]=true;
    }

    int sum=0;
    while(q.size())
    {
        int t=q.front();
        q.pop();
        st[t]=false;

        for(int i=h[t];i!=-1;i=ne[i])
        {
            int j=e[i];
            if(dis[j]<dis[t]+w[i]-mid)
            {
                dis[j]=dis[t]+w[i]-mid;
                cnt[j]=cnt[t]+1;
                sum++;
                if(cnt[j]>=n) return true;
                if(sum>4*n) return true;
                if(!st[j])
                {
                    q.push(j);
                    st[j]=true;
                }
            }
        }
    }
    return false;
}
int main()
{
    while(true)
    {
        memset(h,-1,sizeof h);
        cin>>n;
        if(n==0)
            break;
        for(int i=1;i<=n;i++)
        {
            string str;
            cin>>str;
            int len=str.length();
            if(len<2) continue;
            string left=str.substr(0,2),right=str.substr(len-2);
            int a=(left[0]-'a')*26+left[1]-'a',b=(right[0]-'a')*26+right[1]-'a';
            add(a,b,len);
        }

        n=26*26;
        if(check(0))
        {
            double l=0,r=1010;
            while(r-l>1e-4)
            {
                double mid=(l+r)/2;
                if(check(mid)) l=mid;
                else r=mid;
            }
            printf("%.2f\n",r);
        }
        else
            cout<<"No solution"<<endl;
    }
    return 0;
}

3.8 差分约束

3.8.1 1169. 糖果

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=100010,M=300010;

int n,m;
LL dis[N];
int cnt[N];
bool st[N];
int h[N],e[M],w[M],ne[M],idx;
void add(int a,int b,int c)
{
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}

bool spfa()
{
    memset(dis,-0x3f,sizeof dis);
    dis[0]=0;
    stack<int> q;
    q.push(0);
    st[0]=true;

    int sum=0;
    while(q.size())
    {
        int t=q.top();
        q.pop();
        st[t]=false;

        for(int i=h[t];i!=-1;i=ne[i])
        {
            int j=e[i];
            if(dis[j]<dis[t]+w[i])
            {
                dis[j]=dis[t]+w[i];
                cnt[j]=cnt[t]+1;
                sum++;
                if(sum>10*n) return false;
                if(cnt[j]>=n+1) return false;
                if(!st[j])
                {
                    q.push(j);
                    st[j]=true;
                }
            }
        }
    }
    return true;
}
int main()
{
    cin>>n>>m;
    memset(h,-1,sizeof h);

    for(int i=0;i<m;i++)
    {
        int x,a,b;
        cin>>x>>a>>b;
        if(x==1) add(a,b,0),add(b,a,0);
        else if(x==2) add(a,b,1);
        else if(x==3) add(b,a,0);
        else if(x==4) add(b,a,1);
        else add(a,b,0);
    }

    for(int i=1;i<=n;i++) add(0,i,1);

    if(!spfa())
    {
        cout<<-1<<endl;
    }
    else
    {
        LL res=0;
        for(int i=1;i<=n;i++)
            res+=dis[i];

        cout<<res;
    }
    return 0;
}

3.8.2 362. 区间

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=50010,M=150010;

int n;
int dis[N];
bool st[N];
int h[N],e[M],w[M],ne[M],idx;
void add(int a,int b,int c)
{
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}

void spfa()
{
    memset(dis,-0x3f,sizeof dis);
    dis[0]=0;
    queue<int> q;
    q.push(0);

    while(q.size())
    {
        int t=q.front();
        q.pop();
        st[t]=false;

        for(int i=h[t];i!=-1;i=ne[i])
        {
            int j=e[i];
            if(dis[j]<dis[t]+w[i])
            {
                dis[j]=dis[t]+w[i];
                if(!st[j])
                {
                    q.push(j);
                    st[j]=true;
                }
            }
        }
    }
}
int main()
{
    memset(h,-1,sizeof h);

    cin>>n;
    for(int i=1;i<=50001;i++)
    {
        add(i-1,i,0);
        add(i,i-1,-1);
    }

    for(int i=0;i<n;i++)
    {
        int a,b,c;
        cin>>a>>b>>c;
        a++,b++;
        add(a-1,b,c);
    }

    spfa();

    cout<<dis[50001];
    return 0;
}

3.8.3 1170. 排队布局

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1010,M=30010;
int n,L,D;
int dis[N],cnt[N];
bool st[N];

int h[N],e[M],w[M],ne[M],idx;
void add(int a,int b,int c)
{
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}

bool spfa(int x)
{
    memset(dis,0x3f,sizeof dis);
    memset(st,0,sizeof st);
    memset(cnt,0,sizeof cnt);

    queue<int> q;
    for(int i=1;i<=x;i++)
    {
        q.push(i);
        dis[i]=0;
        st[i]=true;
    }

    while(q.size())
    {
        int t=q.front();
        q.pop();
        st[t]=false;

        for(int i=h[t];i!=-1;i=ne[i])
        {
            int j=e[i];
            if(dis[j]>dis[t]+w[i])
            {
                dis[j]=dis[t]+w[i];
                cnt[j]=cnt[t]+1;
                if(cnt[j]>=n) return true;
                if(!st[j])
                {
                    q.push(j);
                    st[j]=true;
                }
            }
        }
    }
    return false;
}
int main()
{
    memset(h,-1,sizeof h);

    cin>>n>>L>>D;

    for(int i=1;i<n;i++)
        add(i+1,i,0);

    for(int i=0;i<L;i++)
    {
        int a,b,c;
        cin>>a>>b>>c;
        int _min=min(a,b),_max=max(a,b);

        add(_min,_max,c);
    }

    for(int i=0;i<D;i++)
    {
        int a,b,c;
        cin>>a>>b>>c;
        int _min=min(a,b),_max=max(a,b);
        add(_max,_min,-c);
    }

    if(spfa(n))
        cout<<-1<<endl;
    else
    {
        spfa(1);
        if(dis[n]==0x3f3f3f3f) cout<<-2<<endl;
        else cout<<dis[n]<<endl;
    }
    return 0;
}

3.8.4 393. 雇佣收银员

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=30,M=100;

int n;
int dis[N],cnt[N];
int r[N],num[N];
bool st[N];
int h[N],e[M],w[M],ne[M],idx;
void add(int a,int b,int c)
{
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}

void build(int c)
{
    memset(h,-1,sizeof h);
    idx=0;

    for(int i=1;i<=24;i++)
    {
        add(i-1,i,0);
        add(i,i-1,-num[i]);
    }
    for(int i=1;i<=7;i++) add(i+16,i,r[i]-c);
    for(int i=8;i<=24;i++) add(i-8,i,r[i]);

    add(0,24,c),add(24,0,-c);
}
bool spfa(int c)
{
    build(c);

    memset(dis,-0x3f,sizeof dis);
    memset(cnt,0,sizeof cnt);
    memset(st,0,sizeof st);

    queue<int> q;
    q.push(0);
    dis[0]=0;
    st[0]=true;

    while(q.size())
    {
        int t=q.front();
        q.pop();
        st[t]=false;

        for(int i=h[t];i!=-1;i=ne[i])
        {
            int j=e[i];
            if(dis[j]<dis[t]+w[i])
            {
                dis[j]=dis[t]+w[i];
                cnt[j]=cnt[t]+1;
                if(cnt[j]>=25) return false;
                if(!st[j])
                {
                    q.push(j);
                    st[j]=true;
                }
            }
        }
    }
    return true;
}
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        for(int i=1;i<=24;i++) cin>>r[i];
        cin>>n;
        memset(num,0,sizeof num);
        for(int i=0;i<n;i++)
        {
            int t;
            cin>>t;
            num[t+1]++;
        }

        bool success=false;
        for(int i=0;i<=1000;i++)
        {
            if(spfa(i))
            {
                cout<<i<<endl;
                success=true;
                break;
            }
        }
        if(!success)
            cout<<"No Solution"<<endl;
    }
    return 0;
}

3.9 最近公共祖先

3.9.1 1172. 祖孙询问

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=40010,M=80010;

int n,m;
int fa[N][16],depth[N];
int h[N],e[M],ne[M],idx;
void add(int a,int b)
{
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

void bfs(int root)
{
    memset(depth,0x3f,sizeof depth);
    depth[0]=0,depth[root]=1;
    queue<int> q;
    q.push(root);

    while(q.size())
    {
        int t=q.front();
        q.pop();

        for(int i=h[t];i!=-1;i=ne[i])
        {
            int j=e[i];
            if(depth[j]>depth[t]+1)
            {
                depth[j]=depth[t]+1;
                fa[j][0]=t;
                q.push(j);

                for(int k=1;k<=15;k++)
                {
                    fa[j][k]=fa[fa[j][k-1]][k-1];
                }
            }
        }
    }
}

int lca(int a,int b)
{
    if(depth[a]<depth[b]) swap(a,b);

    for(int k=15;k>=0;k--)
    {
        if(depth[fa[a][k]]>=depth[b])
            a=fa[a][k];
    }

    if(a==b) return a;

    for(int k=0;k<=15;k++)
    {
        if(fa[a][k]!=fa[b][k])
        {
            a=fa[a][k];
            b=fa[b][k];
        }
    }

    return fa[a][0];
}
int main()
{
    memset(h,-1,sizeof h);

    cin>>n;
    int root;
    for(int i=0;i<n;i++)
    {
        int a,b;
        cin>>a>>b;
        if(b==-1) root=a;
        else
        {
            add(a,b),add(b,a);
        }
    }

    bfs(root);

    cin>>m;
    while(m--)
    {
        int a,b;
        cin>>a>>b;
        int p=lca(a,b);

        if(p==a) cout<<1<<endl;
        else if(p==b) cout<<2<<endl;
        else cout<<0<<endl;
    }
    return 0;
}

3.9.2 1171. 距离

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;//first保存相关的查询节点编号,second保存查询编号
const int N=10010,M=20010;

int n,m;
int dis[N];
int p[N];
int res[M];
int st[N];
vector<PII> query[N];
int h[N],e[M],w[M],ne[M],idx;
void add(int a,int b,int c)
{
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
int findP(int x)
{
    if(p[x]!=x) return p[x]=findP(p[x]);
    return p[x];
}

void dfs(int u,int fa)
{
    for(int i=h[u];i!=-1;i=ne[i])
    {
        int j=e[i];
        if(j==fa) continue;
        dis[j]=dis[u]+w[i];
        dfs(j,u);
    }
}

void tarjan(int u)
{
    st[u]=1;
    for(int i=h[u];i!=-1;i=ne[i])
    {
        int j=e[i];
        if(!st[j])
        {
            tarjan(j);
            p[j]=u;
        }
    }

    for(int i=0;i<query[u].size();i++)
    {
        PII t=query[u][i];
        int y=t.first,id=t.second;
        if(st[y]==2)
        {
            int anc=findP(y);
            res[id]=dis[u]+dis[y]-2*dis[anc];
        }
    }

    st[u]=2;
}
int main()
{
    memset(h,-1,sizeof h);

    cin>>n>>m;
    for(int i=0;i<n-1;i++)
    {
        int a,b,c;
        cin>>a>>b>>c;
        add(a,b,c),add(b,a,c);
    }

    for(int i=0;i<m;i++)
    {
        int a,b;
        cin>>a>>b;
        if(a!=b)
        {
            query[a].push_back(make_pair(b,i));
            query[b].push_back(make_pair(a,i));
        }
    }

    for(int i=1;i<=n;i++) p[i]=i;

    dfs(1,-1);

    tarjan(1);

    for(int i=0;i<m;i++)
    {
        cout<<res[i]<<endl;
    }
    return 0;
}

3.9.3 356. 次小生成树

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=100010,M=300010,INF=0x3f3f3f3f;

int n,m;
int p[N];
int depth[N],fa[N][17],d1[N][17],d2[N][17];
int q[N];
struct Edge{
    int a,b,w;
    bool used;
    bool operator < (const Edge &t) const
    {
        return w<t.w;
    }
}edge[M];
int h[N],e[M],w[M],ne[M],idx;
void add(int a,int b,int c)
{
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
int findP(int x)
{
    if(p[x]!=x) return p[x]=findP(p[x]);
    return p[x];
}

LL kruskal()
{
    for(int i=1;i<=n;i++) p[i]=i;

    sort(edge,edge+m);

    LL res=0;
    for(int i=0;i<m;i++)
    {
        int a=findP(edge[i].a),b=findP(edge[i].b),w=edge[i].w;
        if(a!=b)
        {
            p[a]=b;
            res+=w;
            edge[i].used=true;
        }
    }
    return res;
}

void build()
{
    memset(h,-1,sizeof h);

    for(int i=0;i<m;i++)
    {
        if(edge[i].used)
        {
            int a=edge[i].a,b=edge[i].b,w=edge[i].w;
            add(a,b,w),add(b,a,w);
        }
    }
}

void bfs()
{
    memset(depth,0x3f,sizeof depth);
    depth[0]=0,depth[1]=1;
    queue<int> q;
    q.push(1);
    while(q.size())
    {
        int t=q.front();
        q.pop();
        for(int i=h[t];i!=-1;i=ne[i])
        {
            int j=e[i];
            if(depth[j]>depth[t]+1)
            {
                depth[j]=depth[t]+1;
                q.push(j);
                fa[j][0]=t;
                d1[j][0]=w[i],d2[j][0]=-INF;
                for(int k=1;k<=16;k++)
                {
                    int anc=fa[j][k-1];
                    fa[j][k]=fa[anc][k-1];
                    int distance[4]={d1[j][k-1],d2[j][k-1],d1[anc][k-1],d2[anc][k-1]};
                    d1[j][k]=d2[j][k]=-INF;
                    for(int u=0;u<4;u++)
                    {
                        int d=distance[u];
                        if(d>d1[j][k]) d2[j][k]=d1[j][k],d1[j][k]=d;
                        else if(d!=d1[j][k]&&d>d2[j][k]) d2[j][k]=d;
                    }
                }
            }
        }
    }
}

int lca(int a,int b,int w)
{
    static int distance[2*N];
    int cnt=0;
    if(depth[a]<depth[b]) swap(a,b);
    for(int k=16;k>=0;k--)
    {
        if(depth[fa[a][k]]>=depth[b])
        {
            distance[cnt++]=d1[a][k];
            distance[cnt++]=d2[a][k];
            a=fa[a][k];
        }
    }
    if(a!=b)
    {
        for(int k=16;k>=0;k--)
        {
            if(fa[a][k]!=fa[b][k])
            {
                distance[cnt++]=d1[a][k];
                distance[cnt++]=d2[a][k];
                distance[cnt++]=d1[b][k];
                distance[cnt++]=d2[b][k];
                a=fa[a][k],b=fa[b][k];
            }
        }
        distance[cnt++]=d1[a][0];
        distance[cnt++]=d1[b][0];
    }

    int dist1=-INF,dist2=-INF;
    for(int i=0;i<cnt;i++)
    {
        int d=distance[i];
        if(d>dist1) dist2=dist1,dist1=d;
        else if(d!=dist1&&d>dist2) dist2=d;
    }

    if(w>dist1) return w-dist1;
    if(w>dist2) return w-dist2;
    return INF;
}
int main()
{
    cin>>n>>m;
    for(int i=0;i<m;i++)
    {
        int a,b,c;
        cin>>a>>b>>c;
        edge[i].a=a,edge[i].b=b,edge[i].w=c;
    }

    LL sum=kruskal();
    build();
    bfs();

    LL res=1e18;
    for(int i=0;i<m;i++)
    {
        if(!edge[i].used)
        {
            int a=edge[i].a,b=edge[i].b,w=edge[i].w;
            res=min(res,sum+lca(a,b,w));
        }
    }
    cout<<res;
    return 0;
}

3.9.4 352. 闇の連鎖

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=100010,M=200010;

int n,m;
int depth[N],fa[N][17];
int d[N];
int ans;
int h[N],e[M],ne[M],idx;
void add(int a,int b)
{
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

void bfs()
{
    memset(depth,0x3f,sizeof depth);
    depth[0]=0,depth[1]=1;
    queue<int> q;
    q.push(1);

    while(q.size())
    {
        int t=q.front();
        q.pop();
        for(int i=h[t];i!=-1;i=ne[i])
        {
            int j=e[i];
            if(depth[j]>depth[t]+1)
            {
                depth[j]=depth[t]+1;
                q.push(j);
                fa[j][0]=t;
                for(int k=1;k<=16;k++)
                {
                    fa[j][k]=fa[fa[j][k-1]][k-1];
                }
            }
        }
    }
}

int lca(int a,int b)
{
    if(depth[a]<depth[b]) swap(a,b);
    for(int k=16;k>=0;k--)
    {
        if(depth[fa[a][k]]>=depth[b])
            a=fa[a][k];
    }
    if(a==b) return a;
    for(int k=16;k>=0;k--)
    {
        if(fa[a][k]!=fa[b][k])
        {
            a=fa[a][k];
            b=fa[b][k];
        }
    }
    return fa[a][0];
}

int dfs(int u,int father)
{
    int res=d[u];
    for(int i=h[u];i!=-1;i=ne[i])
    {
        int j=e[i];
        if(j!=father)
        {
            int s=dfs(j,u);
            if(s==0) ans+=m;
            else if(s==1) ans++;
            res+=s;
        }
    }
    return res;
}
int main()
{
    memset(h,-1,sizeof h);

    cin>>n>>m;
    for(int i=0;i<n-1;i++)
    {
        int a,b;
        cin>>a>>b;
        add(a,b),add(b,a);
    }

    bfs();

    for(int i=0;i<m;i++)
    {
        int a,b;
        cin>>a>>b;
        int p=lca(a,b);
        d[a]+=1,d[b]+=1,d[p]-=2;
    }

    dfs(1,-1);

    cout<<ans;
    return 0;
}

3.10 有向图的强连通分量

3.10.1 1174. 受欢迎的牛

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=10010,M=50010;

int n,m;
int dfn[N],low[N],timestamp;
stack<int> stk;
bool in_stk[N];
int id[N],scc_cnt,sz[N];
int dout[N];
int h[N],e[M],ne[M],idx;
void add(int a,int b)
{
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

void tarjan(int u)
{
    dfn[u]=low[u]=++timestamp;
    stk.push(u),in_stk[u]=true;
    for(int i=h[u];i!=-1;i=ne[i])
    {
        int j=e[i];
        if(!dfn[j])
        {
            tarjan(j);
            low[u]=min(low[u],low[j]);
        }
        else if(in_stk[j])
            low[u]=min(low[u],dfn[j]);
    }

    if(dfn[u]==low[u])
    {
        ++scc_cnt;
        int y;
        do{
            y=stk.top();
            stk.pop();
            in_stk[y]=false;
            id[y]=scc_cnt;
            sz[scc_cnt]++;
        }while(y!=u);
    }
}
int main()
{
    memset(h,-1,sizeof h);

    cin>>n>>m;
    while(m--)
    {
        int a,b;
        cin>>a>>b;
        add(a,b);
    }

    for(int i=1;i<=n;i++)
    {
        if(!dfn[i])
            tarjan(i);
    }

    for(int i=1;i<=n;i++)
    {
        for(int j=h[i];j!=-1;j=ne[j])
        {
            int k=e[j];
            int a=id[i],b=id[k];
            if(a!=b) dout[a]++;
        }
    }

    int zeros=0,sum=0;
    for(int i=1;i<=scc_cnt;i++)
    {
        if(!dout[i])
        {
            zeros++;
            sum+=sz[i];
            if(zeros>1)
            {
                sum=0;
                break;
            }
        }
    }
    cout<<sum;
    return 0;
}

3.10.2 367. 学校网络

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=110,M=10010;

int n;
int dfn[N],low[N],timestamp;
stack<int> stk;
bool in_stk[N];
int id[N],scc_cnt,sz[N];
int din[N],dout[N];
int h[N],e[M],ne[M],idx;
void add(int a,int b)
{
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

void tarjan(int u)
{
    dfn[u]=low[u]=++timestamp;
    stk.push(u),in_stk[u]=true;
    for(int i=h[u];i!=-1;i=ne[i])
    {
        int j=e[i];
        if(!dfn[j])
        {
            tarjan(j);
            low[u]=min(low[u],low[j]);
        }
        else if(in_stk[j]) low[u]=min(low[u],dfn[j]);
    }

    if(dfn[u]==low[u])
    {
        ++scc_cnt;
        int y;
        do{
            y=stk.top();
            stk.pop();
            in_stk[y]=false;
            id[y]=scc_cnt;
            sz[scc_cnt]++;
        }while(y!=u);
    }
}
int main()
{
    memset(h,-1,sizeof h);
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        while(true)
        {
            int b;
            cin>>b;
            if(b==0) break;
            add(i,b);
        }
    }

    for(int i=1;i<=n;i++)
    {
        if(!dfn[i])
            tarjan(i);
    }

    for(int i=1;i<=n;i++)
    {
        for(int j=h[i];j!=-1;j=ne[j])
        {
            int k=e[j];
            int a=id[i],b=id[k];
            if(a!=b) din[b]++,dout[a]++;
        }
    }

    int p=0,q=0;
    for(int i=1;i<=scc_cnt;i++)
    {
        if(!din[i]) p++;
        if(!dout[i]) q++;
    }
    cout<<p<<endl;
    if(scc_cnt==1)
        cout<<0<<endl;
    else
        cout<<max(p,q)<<endl;
    return 0;
}

3.10.3 1175. 最大半连通子图

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=100010,M=2000010;

int n,m,mod;
int dfn[N],low[N],timestamp;
stack<int> stk;
bool in_stk[N];
int id[N],scc_cnt,sz[N];
int f[N],g[N];
int h[N],hs[N],e[M],ne[M],idx;
void add(int h[],int a,int b)
{
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

void tarjan(int u)
{
    dfn[u]=low[u]=++timestamp;
    stk.push(u),in_stk[u]=true;

    for(int i=h[u];i!=-1;i=ne[i])
    {
        int j=e[i];
        if(!dfn[j])
        {
            tarjan(j);
            low[u]=min(low[u],low[j]);
        }
        else if(in_stk[j]) low[u]=min(low[u],dfn[j]);
    }

    if(dfn[u]==low[u])
    {
        ++scc_cnt;
        int y;
        do{
            y=stk.top();
            stk.pop();
            in_stk[y]=false;
            id[y]=scc_cnt;
            sz[scc_cnt]++;
        }while(y!=u);
    }
}
int main()
{
    memset(h,-1,sizeof h);
    memset(hs,-1,sizeof hs);

    cin>>n>>m>>mod;
    while(m--)
    {
        int a,b;
        cin>>a>>b;
        add(h,a,b);
    }

    for(int i=1;i<=n;i++)
    {
        if(!dfn[i])
            tarjan(i);
    }

    unordered_set<LL> S;
    for(int i=1;i<=n;i++)
    {
        for(int j=h[i];j!=-1;j=ne[j])
        {
            int k=e[j];
            int a=id[i],b=id[k];
            LL ha=a*1000000ll+b;
            if(a!=b&&!S.count(ha))
            {
                add(hs,a,b);
                S.insert(ha);
            }
        }
    }

    for(int i=scc_cnt;i>0;i--)
    {
        if(!f[i])
        {
            f[i]=sz[i];
            g[i]=1;
        }
        for(int j=hs[i];j!=-1;j=ne[j])
        {
            int k=e[j];
            if(f[k]<f[i]+sz[k])
            {
                f[k]=f[i]+sz[k];
                g[k]=g[i];
            }
            else if(f[k]==f[i]+sz[k])
                g[k]=(g[k]+g[i])%mod;
        }
    }

    int maxf=0,sum=0;
    for(int i=1;i<=scc_cnt;i++)
    {
        if(f[i]>maxf)
        {
            maxf=f[i];
            sum=g[i];
        }
        else if(f[i]==maxf) sum=(sum+g[i])%mod;
    }

    cout<<maxf<<endl;
    cout<<sum<<endl;
    return 0;
}

3.10.4 368. 银河

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=100010,M=600010;

int n,m;
int dfn[N],low[N],timestamp;
stack<int> stk;
bool in_stk[N];
int id[N],scc_cnt,sz[N];
int dis[N];
int h[N],hs[N],e[M],w[M],ne[M],idx;
void add(int h[],int a,int b,int c)
{
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}

void tarjan(int u)
{
    dfn[u]=low[u]=++timestamp;
    stk.push(u),in_stk[u]=true;

    for(int i=h[u];i!=-1;i=ne[i])
    {
        int j=e[i];
        if(!dfn[j])
        {
            tarjan(j);
            low[u]=min(low[u],dfn[j]);
        }
        else if(in_stk[j]) low[u]=min(low[u],dfn[j]);
    }

    if(dfn[u]==low[u])
    {
        ++scc_cnt;
        int y;
        do{
            y=stk.top();
            stk.pop();
            in_stk[y]=false;
            id[y]=scc_cnt;
            sz[scc_cnt]++;
        }while(y!=u);
    }
}
int main()
{
    memset(h,-1,sizeof h);
    memset(hs,-1,sizeof hs);

    cin>>n>>m;
    for(int i=1;i<=n;i++)
        add(h,0,i,1);

    while(m--)
    {
        int t,a,b;
        cin>>t>>a>>b;
        if(t==1) add(h,b,a,0),add(h,a,b,0);
        else if(t==2) add(h,a,b,1);
        else if(t==3) add(h,b,a,0);
        else if(t==4) add(h,b,a,1);
        else add(h,a,b,0);
    }

    tarjan(0);

    bool success=true;
    for(int i=0;i<=n;i++)
    {
        for(int j=h[i];j!=-1;j=ne[j])
        {
            int k=e[j];
            int a=id[i],b=id[k];
            if(a==b)
            {
                if(w[j]>0)
                {
                    success=false;
                    break;
                }
            }
            else add(hs,a,b,w[j]);
        }
        if(!success) break;
    }

    if(!success) cout<<-1<<endl;
    else
    {
        for(int i=scc_cnt;i>0;i--)
        {
            for(int j=hs[i];j!=-1;j=ne[j])
            {
                int k=e[j];
                dis[k]=max(dis[k],dis[i]+w[j]);
            }
        }

        LL res=0;
        for(int i=1;i<=scc_cnt;i++) res+=(LL)dis[i]*sz[i];

        cout<<res;
    }
    return 0;
}

3.11 无向图的双连通分量

3.11.1 395. 冗余路径

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=5010,M=20010;

int n,m;
int dfn[N],low[N],timestamp;
stack<int> stk;
int id[N],dcc_cnt;
bool is_bridge[M];
int d[N];
int h[N],e[M],ne[M],idx;
void add(int a,int b)
{
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

void tarjan(int u,int from)
{
    dfn[u]=low[u]=++timestamp;
    stk.push(u);

    for(int i=h[u];i!=-1;i=ne[i])
    {
        int j=e[i];
        if(!dfn[j])
        {
            tarjan(j,i);
            low[u]=min(low[u],low[j]);
            if(dfn[u]<low[j])
            {
                is_bridge[i]=is_bridge[i^1]=true;
            }
        }
        else if(i!=(from^1))
            low[u]=min(low[u],dfn[j]);
    }

    if(dfn[u]==low[u])
    {
        ++dcc_cnt;
        int y;
        do{
            y=stk.top();
            stk.pop();
            id[y]=dcc_cnt;
        }while(y!=u);
    }
}
int main()
{
    memset(h,-1,sizeof h);

    cin>>n>>m;
    while(m--)
    {
        int a,b;
        cin>>a>>b;
        add(a,b),add(b,a);
    }

    tarjan(1,-1);

    for(int i=0;i<idx;i++)
    {
        if(is_bridge[i])
            d[id[e[i]]]++;
    }

    int cnt=0;
    for(int i=1;i<=dcc_cnt;i++)
        if(d[i]==1)
            cnt++;

    cout<<(cnt+1)/2;
    return 0;
}

3.11.2 1183. 电力

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=100010,M=300010;

int n,m;
int dfn[N],low[N],timestamp;
int root,ans;
int h[N],e[M],ne[M],idx;
void add(int a,int b)
{
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

void tarjan(int u)
{
    dfn[u]=low[u]=++timestamp;

    int cnt=0;
    for(int i=h[u];i!=-1;i=ne[i])
    {
        int j=e[i];
        if(!dfn[j])
        {
            tarjan(j);
            low[u]=min(low[u],low[j]);
            if(low[j]>=dfn[u]) cnt++;
        }
        else low[u]=min(low[u],dfn[j]);
    }

    if(u!=root) cnt++;

    ans=max(ans,cnt);
}

int main()
{
    while(true)
    {
        cin>>n>>m;
        if(n==0&&m==0) break;
        memset(h,-1,sizeof h);
        memset(dfn,0,sizeof dfn);
        idx=timestamp=0;

        while(m--)
        {
            int a,b;
            cin>>a>>b;
            add(a,b),add(b,a);
        }

        ans=0;
        int cnt=0;
        for(root=0;root<n;root++)
        {
            if(!dfn[root])
            {
                cnt++;
                tarjan(root);
            }
        }

        cout<<ans+cnt-1<<endl;
    }
    return 0;
}

3.11.3 396. 矿场搭建

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ULL;
const int N=1010,M=1010;

int n,m;
int dfn[N],low[N],timestamp;
stack<int> stk;
int dcc_cnt;
vector<int> dcc[N];
bool cut[N];
int root;
int h[N],e[M],ne[M],idx;
void add(int a,int b)
{
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

void tarjan(int u)
{
    dfn[u]=low[u]=++timestamp;
    stk.push(u);

    if(u==root&&h[u]==-1)
    {
        dcc_cnt++;
        dcc[dcc_cnt].push_back(u);
        return;
    }

    int cnt=0;
    for(int i=h[u];i!=-1;i=ne[i])
    {
        int j=e[i];
        if(!dfn[j])
        {
            tarjan(j);
            low[u]=min(low[u],low[j]);
            if(dfn[u]<=low[j])
            {
                cnt++;
                if(u!=root||cnt>1) cut[u]=true;
                ++dcc_cnt;
                int y;
                do{
                    y=stk.top();
                    stk.pop();
                    dcc[dcc_cnt].push_back(y);
                }while(y!=j);
                dcc[dcc_cnt].push_back(u);
            }
        }
        else low[u]=min(low[u],dfn[j]);
    }
}
int main()
{
    int T=1;
    while(true)
    {
        cin>>m;
        if(m==0) break;
        memset(h,-1,sizeof h);
        memset(dfn,0,sizeof dfn);
        memset(cut,0,sizeof cut);
        for(int i=0;i<N;i++) dcc[i].clear();
        idx=n=timestamp=dcc_cnt=0;

        while(m--)
        {
            int a,b;
            cin>>a>>b;
            add(a,b),add(b,a);
            n=max(n,a);
            n=max(n,b);
        }

        for(root=1;root<=n;root++)
        {
            if(!dfn[root])
                tarjan(root);
        }

        int res=0;
        ULL num=1;
        for(int i=1;i<=dcc_cnt;i++)
        {
            int cnt=0;
            for(int j=0;j<dcc[i].size();j++)
            {
                if(cut[dcc[i][j]])
                    cnt++;
            }

            if(cnt==0)
            {
                if(dcc[i].size()>1) res+=2,num*=dcc[i].size()*(dcc[i].size()-1)/2;
                else res++;
            }
            else if(cnt==1) res++,num*=dcc[i].size()-1;
        }
        cout<<"Case "<<T<<": "<<res<<" "<<num<<endl;
        T++;
    }

    return 0;
}

3.12 二分图

3.12.1 257. 关押罪犯

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=20010,M=200010;

int n,m;
int color[N];   //0表示未染色,1表示染白色,2表示染黑色
int h[N],e[M],w[M],ne[M],idx;
void add(int a,int b,int c)
{
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}

bool dfs(int u,int c,int mid)
{
    color[u]=c;
    for(int i=h[u];i!=-1;i=ne[i])
    {
        int j=e[i];
        if(w[i]<=mid) continue;
        if(color[j])
        {
            if(color[j]==c) return false;
        }
        else if(!dfs(j,3-c,mid)) return false;
    }
    return true;
}

bool check(int mid)
{
    memset(color,0,sizeof color);

    for(int i=1;i<=n;i++)
    {
        if(!color[i])
        {
            if(!dfs(i,1,mid))
                return false;
        }
    }
    return true;
}
int main()
{
    memset(h,-1,sizeof h);

    cin>>n>>m;
    while(m--)
    {
        int a,b,c;
        cin>>a>>b>>c;
        add(a,b,c),add(b,a,c);
    }

    int l=0,r=1e9;
    while(l<r)
    {
        int mid=(l+r)/2;
        if(check(mid)) r=mid;
        else l=mid+1;
    }

    cout<<r;
    return 0;
}

3.12.2 372. 棋盘覆盖

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
const int N=110;

int n,t;
PII match[N][N];
int g[N][N];
bool st[N][N];

int dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};
bool findG(int x,int y)
{
    for(int i=0;i<4;i++)
    {
        int a=x+dx[i],b=y+dy[i];
        if(a<1||a>n||b<1||b>n) continue;
        if(st[a][b]||g[a][b]) continue;
        st[a][b]=true;
        PII t=match[a][b];
        if(t.first==-1||findG(t.first,t.second))
        {
            match[a][b]=make_pair(x,y);
            return true;
        }
    }
    return false;
}
int main()
{
    cin>>n>>t;
    while(t--)
    {
        int x,y;
        cin>>x>>y;
        g[x][y]=true;
    }

    memset(match,-1,sizeof match);

    int res=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if((i+j)%2&&!g[i][j])
            {
                memset(st,0,sizeof st);
                if(findG(i,j)) res++;
            }
        }
    }

    cout<<res;
    return 0;
}

3.12.3 376. 机器任务

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=110;

int n,m,k;
int match[N];
bool g[N][N],st[N];

bool findG(int x)
{
    for(int i=1;i<m;i++)
    {
        if(!st[i]&&g[x][i])
        {
            st[i]=true;
            if(match[i]==-1||findG(match[i]))
            {
                match[i]=x;
                return true;
            }
        }
    }
    return false;
}
int main()
{
    while(true)
    {
        cin>>n;
        if(n==0) break;
        cin>>m>>k;
        memset(g,0,sizeof g);
        memset(match,-1,sizeof match);

        while(k--)
        {
            int t,a,b;
            cin>>t>>a>>b;
            if(!a||!b) continue;
            g[a][b]=true;
        }

        int res=0;
        for(int i=1;i<n;i++)
        {
            memset(st,0,sizeof st);
            if(findG(i)) res++;
        }

        cout<<res<<endl;
    }
    return 0;
}

3.12.4 378. 骑士放置

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
const int N=110;

int n,m,t;
int g[N][N];
PII match[N][N];
bool st[N][N];

int dx[8]={-2,-1,1,2,2,1,-1,-2},dy[8]={1,2,2,1,-1,-2,-2,-1};
bool findG(int x,int y)
{
    for(int i=0;i<8;i++)
    {
        int a=x+dx[i],b=y+dy[i];
        if(a<1||a>n||b<1||b>m) continue;
        if(st[a][b]||g[a][b]) continue;
        st[a][b]=true;
        PII t=match[a][b];
        if(t.first==-1||findG(t.first,t.second))
        {
            match[a][b]=make_pair(x,y);
            return true;
        }
    }
    return false;
}
int main()
{
    cin>>n>>m>>t;
    for(int i=0;i<t;i++)
    {
        int x,y;
        cin>>x>>y;
        g[x][y]=true;
    }

    memset(match,-1,sizeof match);

    int res=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            if((i+j)%2&&!g[i][j])
            {
                memset(st,0,sizeof st);
                if(findG(i,j)) res++;
            }
        }
    }

    cout<<n*m-res-t;
    return 0;
}

3.12.5 379. 捉迷藏

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=210;

int n,m;
int match[N];
bool st[N],d[N][N];

bool findG(int x)
{
    for(int i=1;i<=n;i++)
    {
        if(d[x][i]&&!st[i])
        {
            st[i]=true;
            int t=match[i];
            if(t==0||findG(t))
            {
                match[i]=x;
                return true;
            }
        }
    }
    return false;
}
int main()
{
    cin>>n>>m;
    for(int i=0;i<m;i++)
    {
        int a,b;
        cin>>a>>b;
        d[a][b]=true;
    }

    //求传递闭包
    for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                d[i][j]|=d[i][k]&d[k][j];

    int res=0;
    for(int i=1;i<=n;i++)
    {
        memset(st,0,sizeof st);

        if(findG(i)) res++;
    }

    cout<<n-res;
    return 0;
}

3.13 欧拉回路和欧拉路径

3.13.1 1123. 铲雪车

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
int main()
{
    double x1,y1,x2,y2;
    cin>>x1>>y1;

    double sum=0;
    while(cin>>x1>>y1>>x2>>y2)
    {
        double dx=x1-x2;
        double dy=y1-y2;
        sum+=sqrt(dx*dx+dy*dy)*2;
    }

    int minutes=round(sum/1000/20*60);
    int hours=minutes/60;
    minutes%=60;

    printf("%d:%02d\n",hours,minutes);
    return 0;
}

3.13.2 1184. 欧拉回路

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=100010,M=400010;

int type;
int n,m;
int ans[M],cnt;
int din[N],dout[N];
int h[N],e[M],ne[M],idx;
bool used[M];
void add(int a,int b)
{
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

void dfs(int u)
{
    for(int &i=h[u];i!=-1;)
    {
        if(used[i])
        {
            i=ne[i];
            continue;
        }

        used[i]=true;
        if(type==1) used[i^1]=true;

        int t;
        if(type==1)
        {
            t=i/2+1;
            if(i&1) t=-t;
        }
        else t=i+1;

        int j=e[i];
        i=ne[i];
        dfs(j);

        ans[++cnt]=t;
    }
}
int main()
{
    memset(h,-1,sizeof h);
    cin>>type;
    cin>>n>>m;

    for(int i=0;i<m;i++)
    {
        int a,b;
        cin>>a>>b;
        add(a,b);
        if(type==1) add(b,a);
        din[b]++,dout[a]++;
    }

    if(type==1)
    {
        for(int i=1;i<=n;i++)
        {
            if(din[i]+dout[i]&1)
            {
                cout<<"NO"<<endl;
                return 0;
            }
        }
    }
    else
    {
        for(int i=1;i<=n;i++)
        {
            if(din[i]!=dout[i])
            {
                cout<<"NO"<<endl;
                return 0;
            }
        }
    }

    for(int i=1;i<=n;i++)
    {
        if(h[i]!=-1)
        {
            dfs(i);
            break;
        }
    }

    if(cnt<m)
    {
        cout<<"NO"<<endl;
        return 0;
    }

    cout<<"YES"<<endl;
    for(int i=cnt;i>0;i--) cout<<ans[i]<<" ";

    return 0;
}

3.13.3 1124. 骑马修栅栏

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=510,M=1100;

int n=500,m;
int g[N][N];
int ans[M],cnt;
int d[N];

void dfs(int u)
{
    for(int i=1;i<=n;i++)
    {
        if(g[u][i])
        {
            g[u][i]--,g[i][u]--;
            dfs(i);
        }
    }

    ans[++cnt]=u;
}
int main()
{
    cin>>m;
    while(m--)
    {
        int a,b;
        cin>>a>>b;
        g[a][b]++,g[b][a]++;
        d[a]++,d[b]++;
    }

    int start=1;
    while(!d[start]) start++;
    for(int i=1;i<=n;i++)
    {
        if(d[i]%2)
        {
            start=i;
            break;
        }
    }

    dfs(start);

    for(int i=cnt;i>0;i--) cout<<ans[i]<<endl;
    return 0;
}

3.13.4 1185. 单词游戏

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=30;
int t,n;
int din[N],dout[N];
int p[N];
bool st[N];

int findP(int x)
{
    if(p[x]!=x) return p[x]=findP(p[x]);
    return p[x];
}

int main()
{
    cin>>t;

    while(t--)
    {
        cin>>n;
        memset(din,0,sizeof din);
        memset(dout,0,sizeof dout);
        memset(st,0,sizeof st);
        for(int i=0;i<26;i++) p[i]=i;

        string str;
        for(int i=0;i<n;i++)
        {
            cin>>str;
            int a=str[0]-'a',b=str[str.length()-1]-'a';
            dout[a]++,din[b]++;
            st[a]=true,st[b]=true;
            p[findP(a)]=findP(b);
        }

        bool flag1=true,flag2=true;
        int start=0,ed=0;
        for(int i=0;i<26;i++)
        {
            if(din[i]!=dout[i])
            {
                flag1=false;
                if(din[i]-dout[i]==1)
                    ed++;
                else if(dout[i]-din[i]==1)
                    start++;
                else
                {
                    flag2=false;
                    break;
                }
            }
        }
        int t=findP(0);
        for(int i=1;i<26;i++)
        {
            if(st[i]&&findP(i)!=t)
            {
                flag1=false;
                break;
            }
        }

        if(flag1||flag2&&start==1&&ed==1)
            cout<<"Ordering is possible."<<endl;
        else
            cout<<"The door cannot be opened."<<endl;
    }
    return 0;
}

3.14 拓扑排序

3.14.1 1191. 家谱树

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=110,M=10010;

int n;
int d[N];
vector<int> ans;
int h[N],e[M],ne[M],idx;
void add(int a,int b)
{
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

void topsort()
{
    queue<int> q;
    for(int i=1;i<=n;i++)
    {
        if(d[i]==0) q.push(i);
    }

    while(q.size())
    {
        int t=q.front();
        q.pop();
        ans.push_back(t);
        for(int i=h[t];i!=-1;i=ne[i])
        {
            int j=e[i];
            d[j]--;
            if(d[j]==0) q.push(j);
        }
    }
}

int main()
{
    memset(h,-1,sizeof h);

    cin>>n;
    for(int i=1;i<=n;i++)
    {
        while(true)
        {
            int x;
            cin>>x;
            if(x==0) break;
            add(i,x);
            d[x]++;
        }
    }

    topsort();

    for(int i=0;i<ans.size();i++)
    {
        cout<<ans[i]<<" ";
    }
    return 0;
}

3.14.2 1192. 奖金

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
const int N=10010,M=20010;

int n,m;
int d[N];
int h[N],e[M],ne[M],idx;
void add(int a,int b)
{
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

int topsort()
{
    int res=0,cnt=0;
    queue<PII> q;
    for(int i=1;i<=n;i++)
    {
        if(d[i]==0)
        {
            q.push(make_pair(i,100));
            res+=100;
            cnt++;
        }
    }

    while(q.size())
    {
        PII t=q.front();
        q.pop();
        for(int i=h[t.first];i!=-1;i=ne[i])
        {
            int j=e[i];
            d[j]--;
            if(d[j]==0)
            {
                res+=t.second+1;
                q.push(make_pair(j,t.second+1));
                cnt++;
            }
        }
    }
    if(cnt<n) return -1;
    return res;
}
int main()
{
    memset(h,-1,sizeof h);

    cin>>n>>m;
    for(int i=0;i<m;i++)
    {
        int a,b;
        cin>>a>>b;
        add(b,a);
        d[a]++;
    }

    int t=topsort();
    if(t==-1) cout<<"Poor Xed"<<endl;
    else cout<<t<<endl;

    return 0;
}

3.14.3 164. 可达性统计

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=30010;

int n,m;
int d[N];
vector<int> seq;
bitset<N> f[N];
int h[N],e[N],ne[N],idx;
void add(int a,int b)
{
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

void topsort()
{
    queue<int> q;
    for(int i=1;i<=n;i++)
    {
        if(d[i]==0)
        {
            q.push(i);
            seq.push_back(i);
        }
    }

    while(q.size())
    {
        int t=q.front();
        q.pop();

        for(int i=h[t];i!=-1;i=ne[i])
        {
            int j=e[i];
            d[j]--;
            if(d[j]==0)
            {
                q.push(j);
                seq.push_back(j);
            }
        }
    }
}
int main()
{
    ios::sync_with_stdio(0);
    memset(h,-1,sizeof h);

    cin>>n>>m;
    for(int i=0;i<m;i++)
    {
        int a,b;
        cin>>a>>b;
        add(a,b);
        d[b]++;
    }

    topsort();

    for(int i=n-1;i>=0;i--)
    {
        int j=seq[i];
        f[j][j]=1;
        for(int k=h[j];k!=-1;k=ne[k])
            f[j]|=f[e[k]];
    }

    for(int i=1;i<=n;i++) cout<<f[i].count()<<endl;

    return 0;
}

3.14.4 456. 车站分级

在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=2010,M=1000010;

int n,m;
int d[N];
bool stop[N];
vector<int> seq;
int dis[N];
int h[N],e[M],w[M],ne[M],idx;
void add(int a,int b,int c)
{
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}

void topsort()
{
    queue<int> q;
    for(int i=1;i<=n+m;i++)
    {
        if(d[i]==0)
        {
            q.push(i);
            seq.push_back(i);
        }
    }

    while(q.size())
    {
        int t=q.front();
        q.pop();

        for(int i=h[t];i!=-1;i=ne[i])
        {
            int j=e[i];
            d[j]--;
            if(d[j]==0)
            {
                q.push(j);
                seq.push_back(j);
            }
        }
    }
}

int main()
{
    memset(h,-1,sizeof h);

    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        int s;
        cin>>s;
        int start,ed;
        memset(stop,0,sizeof stop);
        for(int j=0;j<s;j++)
        {
            int x;
            cin>>x;
            if(j==0) start=x;
            if(j==s-1) ed=x;
            stop[x]=true;
        }

        int vir=n+i;
        for(int j=start;j<=ed;j++)
        {
            if(stop[j])
            {
                add(vir,j,1);
                d[j]++;
            }
            else
            {
                add(j,vir,0);
                d[vir]++;
            }
        }
    }

    topsort();

    for(int i=1;i<=n;i++) dis[i]=1;

    for(int i=0;i<seq.size();i++)
    {
        int t=seq[i];
        for(int j=h[t];j!=-1;j=ne[j])
        {
            int k=e[j];
            dis[k]=max(dis[k],dis[t]+w[j]);
        }
    }

    set<int> eq;
    for(int i=1;i<=n;i++)
        eq.insert(dis[i]);

    cout<<eq.size();

    return 0;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值