某考研群的入群试题

题目描述:

小翟为了完成一篇论文,一共要抄袭n篇文章。其中第i篇文章需要a[i]的时间去完成。小翟可以发动粉丝同时抄袭多篇文章,但存在一些文章,只有当它的若干个前置文章抄袭完成后,才能开始抄袭该文章。同时我们认为小翟和其粉丝在一篇文章的前置文章都完成后,能马上开始抄袭该文章。为了让小翟尽快完成论文,获得博士学位,在最优的情况下,小翟的论文什么时候可以完成?

小翟虽然不知道知网,但是他想知道在保证论文尽快完成的情况下(即保证上题答案不变情况),每篇文章最早什么时候可以开始抄袭,和最晚什么时候可以开始抄袭。设第i篇文章最早可以抄袭的时间为f[i];在不影响论文完成时间前提下,第i篇文章最晚可以抄袭的时间为g[i]. 请你回答∏i=0-n (g[i]-f[i]+10) 除以10^9+7所得的余数,题目保证有解。

输入:

第一行输入一个整数n,m
第二行输入n个正整数,a1,a2,…,an描述每篇文章抄袭所需要的时间。
接下来读入m行,每行读入两个整数u,v,表示编号为u的文章是编号为v文章的前置文章
所有的输入数据都满足1<=n<=5*105,1<=m<=106,1<=a[i]<=10^6

输出:

第一行输出一个整数表示论文最早完成时间。
第二行输出一个整数表示∏i=0-n (g[i]-f[i]+10) 除以10^9+7所得的余数

样例输入:

8 9
11 17 16 20 14 12 13 15
1 3
2 4
4 3
3 6
5 6
2 5
6 8
5 7
7 8

样例输出:

80
459599979

备注:

∏i=0-n 为i从0到n的累乘符号

分析:

拓扑排序,关键路径,反向计算最长可能结果。
因为只有题目没有oj 通过了样例不确定代码是不是对的。
仅为保存代码,代码思路仅供参考

代码:

#include <stdio.h>
#include <iostream>
#include <vector>
#include <queue>
#define MAX 1000000007
#define INF 0x3fffffff
using namespace std;

int n,m;
int indegree[50050]={0};//入度
int outdegree[50050]={0};//出度
int tcin[50050];//耗时
vector<int> g[50050];//正向
vector<int> rg[50050];//反向
int tm[50050];//最短时间
int tm2[50050];//最长时间
int pre[50050];//关键路径的前驱
bool vis[50050];
//vector<int> toporder;

int checkvis(int v){
    int res=INF;
    for(int i=0;i<g[v].size();i++){
        if(vis[g[v][i]]==false) return 0;
        else res=min(tm2[g[v][i]]-tcin[g[v][i]],res);
    }
    return res;
}

void calmx(int e){
    int temp=e;
    queue<int> q;
    while(temp!=0){
        tm2[temp]=tm[temp];
        q.push(temp);
        vis[temp]=true;
        temp=pre[temp];
    }
    for(int i=1;i<=n;i++){
        //所有出度为0的点 时间均为tm2[e]
        if(outdegree[i]==0){
            tm2[i]=tm2[e];
            vis[i]=true;
        }
    }
    while(!q.empty()){
        int u=q.front();
        q.pop();
        for(int i=0;i<rg[u].size();i++){
            int v=rg[u][i];
            int tempres;
            if(vis[v]) continue;
            tempres=checkvis(v);
            if(tempres){
                tm2[v]=tempres;
                vis[v]=true;
                q.push(v);
            }
        }
    }
}

void toplogicalsort(){
    queue<int> q;
    for(int i=1;i<=n;i++){
        if(indegree[i]==0){
            q.push(i);
        }
    }
    while(!q.empty()){
        int u=q.front();
        q.pop();
//        toporder.push_back(u);
        for(int i=0;i<g[u].size();i++){
            int v=g[u][i];
            indegree[v]--;
            if(indegree[v]==0){
                q.push(v);
            }
            if(tm[u]+tcin[v]>tm[v]){
                tm[v]=tm[u]+tcin[v];
                pre[v]=u;
            }
        }
    }
}
int findlast(){
    int mx=0,ans=0;
    for(int i=1;i<=n;i++){
        if(tm[i]>mx){
            mx=tm[i];
            ans=i;
        }
    }
    return ans;
}
int main(){
//    freopen("1.txt","r",stdin);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%d",&tcin[i]);
        tm[i]=tcin[i];
    }
    int a,b;
    for(int i=0;i<m;i++){
        scanf("%d%d",&a,&b);
        g[a].push_back(b);
        rg[b].push_back(a);
        indegree[b]++;
        outdegree[a]++;
    }
    toplogicalsort();
    int e=findlast();
    calmx(e);
    long long sum=1;
    for(int i=1;i<=n;i++){
        sum=sum*(tm2[i]-tm[i]+10);
        sum=sum%MAX;
    }
    printf("%d\n%lld\n",tm[e],sum);

    return 0;
//    for(int i=1;i<=n;i++){
//        printf("%d:%d-%d=%d\n",i,tm2[i],tm[i],tm2[i]-tm[i]);
//    }
//    printf("TOPOrder:");
//    for(int i=0;i<toporder.size();i++) printf(" %d",toporder[i]);
//    cout<<endl;
//    for(int i=1;i<=n;i++) printf("pre:%d:%d\n",i,pre[i]);
//    cout<<endl;
//    printf("%d",3459600000%MAX);
}

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值