拓扑排序——CodeForces-645D

题目链接

题目含义

有一个机器人比赛,只要a能打败b,b能打败c,a就一定能打败c

然后给出一堆比赛的结果,如果不能得到唯一的所有的机器人战力排名,就输出-1

如果可以的话,最少能用前几场比赛结果能得到,输出这个最少的比赛次数

题目分析

使用拓扑排序,如果出队数不等于机器人数或者某一时刻队列有两个及以上入度为零的点时都输出-1

而如果满足的话,要找到最少的比赛次数

如果加一条边用一次拓扑排序的话,明显会超时

这里提供两种方法

(1)你有发现拓扑排序每两个点的关系都有在题中给出吗

比如说4-2-1-3的顺序,一定会给出4打败2,2打败1,1打败3

而我们要做的就是在拓扑排序中记录每一场必要的比赛结果

然后在输入里找,当必要的比赛全部出现后,就得到最少的比赛次数了

(2)可以用二分答案,在输入次数里寻找最少的同时也能满足拓扑排序的次数

题目代码

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+7;
int in[maxn],sum,n,m,a[maxn],b[maxn],head[maxn],tot,copyin[maxn];
bool flag;
int fa[maxn],cnt;
struct edge{
    int to,next;
}e[maxn];
bool topusort(){
    queue<int>q;
//    for(int i=1;i<=n;i++)
//        copyin[i]=in[i];
    for(int i=1;i<=n;i++)
        if(!in[i])q.push(i);
    int num=0;
    while(!q.empty()){
        if(q.size()>1)return false;
        int u=q.front();q.pop();
        num++;
        for(int i=head[u];i!=-1;i=e[i].next){
            int v=e[i].to;
            if(--in[v]==0){
                q.push(v);
                fa[v]=u;
                cnt++;
            }
        }
    }return num==n;
}
void add(int u,int v){
    e[tot].to=v;
    e[tot].next=head[u];
    head[u]=tot++;
}
int main(){
    scanf("%d%d",&n,&m);
    memset(head,-1,sizeof(head));
    int k=0;
//    flag=false;
    for(int i=1;i<=m;i++){
        scanf("%d%d",&a[i],&b[i]);
        add(a[i],b[i]);
        in[b[i]]++;
    }
    if(!topusort())printf("-1
");
    else{
        for(int i=1;i<=m;i++){
            if(fa[b[i]]==a[i]){
                cnt--;
                if(cnt==0){
                    printf("%d
",i);
                    break;
                }
            }
        }
    }
    return 0;
}
第一种做法
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
typedef long long LL;
const int maxn=1e5+7;
int head[maxn],tot,in[maxn];
struct edge{
    int to,next;
}e[maxn];
void add(int u,int v){
    e[tot].to=v;
    e[tot].next=head[u];
    head[u]=tot++;
}
int n,m,a[maxn],b[maxn];
bool topusort(int nn){
    memset(head,-1,sizeof(head));
    memset(in,0,sizeof(in));
    tot=0;
    for(int i=1;i<=nn;i++){
        add(a[i],b[i]);
        in[b[i]]++;
    }
    queue<int>q;
    for(int i=1;i<=n;i++)
        if(in[i]==0)q.push(i);
    while(!q.empty()){
        if(q.size()>1)return false;
        int u=q.front();q.pop();
        for(int i=head[u];i!=-1;i=e[i].next){
            int v=e[i].to;
            if(--in[v]==0)q.push(v);
        }
    }
//    cout<<sum<<endl;
    return true;
//    return sum==n;
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
        scanf("%d%d",&a[i],&b[i]);
    int low=1,high=m;
    int ans=-1;
    while(low<=high){
        int mid=(low+high)>>1;
        if(topusort(mid)){
            ans=mid;
            high=mid-1;
        }
        else low=mid+1;
    }
    printf("%d
",ans);
    return 0;
}
第二种做法

不知道为什么,我把in数组在拓扑里定义,用它的默认值,结果会错

原文地址:https://www.cnblogs.com/helman/p/11291727.html