logn.me problem 1044 关键路径

关键路径
Case Time Limit: 2000 MS (Others) / 4000 MS (Java) Case Memory Limit: 256 MB (Others) / 512 MB (Java)
Accepted: 66 Total Submission: 539

查看我的提交显示标签
Problem Description

给定一个有N个顶点、M条边的有向图,顶点下标为从1到N,每条边都有边权。判断这个有向图是否是有向无环图,如果是的话,请处理K个查询,每个查询为图中的一条边,求这条边的最早发生时间和最晚发生时间。最后再输出图中的所有关键路径。
Input

每个输入文件中一组数据。

第一行为两个整数N、M,表示有向无环图的顶点数和边数(1<=N<=1000, 0<=M<=N*(N-1)),顶点编号为从1到N。

接下来M行,每行为三个正整数u、v、w(1<=u,v<=N,0<w<=20,u!=v),分别表示有向边的起点、终点、边权。数据保证不会有两条起点和终点都相同的边。

然后是一个正整数K(1<=K<=1000),表示查询个数。

接着是K行,每行为两个正整数u、v,分别表示查询边的起点和终点。数据保证查询边一定是图上存在的边。
Output

如果给出的图不是有向无环图,那么在一行里输出NO,后面的查询结果和关键路径均不需要输出;

如果给出的图是有向无环图,那么在一行里输出YES,接着输出下面的内容:

每个查询一行,输出查询边的最早发生时间和最晚发生时间;

之后一行输出一个整数:关键路径上的边权之和;

最后若干行输出所有关键路径,每行表示其中一条,格式为用->连接的顶点编号。注意,如果有两条关键路径a[1]->a[2]->…->a[k]->a[k+1]->…与b[1]->b[2]->…->b[k]->[k+1]->…,满足a[1]==b[1]、a[2]==b[2]、…、a[k]==b[k]、a[k+1]<b[k+1],那么把关键路径a优先输出。数据保证关键路径条数不超过10000条。
Sample Input 1

4 5
1 2 3
1 3 2
1 4 5
2 4 1
3 4 3
2
1 3
2 4
Sample Output 1

YES
0 0
3 4
5
1->3->4
1->4
Sample Input 2

3 3
1 2 3
2 3 1
3 2 2
2
1 2
2 3
Sample Output 2

NO
Author

Shoutmon
Source

19浙大考研机试模拟赛

一开始用记忆化搜索,过了9个case一个超时,还是遍历边的次数太多

用拓扑排序正向更新每个节点最早开始时间O(m)
同时将节点放进栈中,逆向遍历更新最晚时间O(m)//正向不只一遍 遍历 边
所有边只遍历一遍(注意逆向遍历的技巧)

注意:源点不只一个,汇点不只一个,注意处理环的优化方式

#include<bits/stdc++.h>
#include<stdlib.h>
using namespace std;
typedef long long LL;
const LL mod = 1e9+7;
const int N = 1000+10;
typedef long long LL;
struct node
{
    int u, v, w, next;
    bool operator <(const node& A)const
    {
        if(u!=A.u)return u<A.u;
        return v>A.v;
    }
} p[N*N], q[N*N];
int head[2*N];
int cnt;

void add(int x,int y,int z)
{
    p[cnt].u=x,p[cnt].v=y,p[cnt].next=head[x],p[cnt].w=z;
    head[x]=cnt++;
    return ;
}
int in[N], last[N][N],  edge[N][N];
int  maxt=0;

int n, m;
queue<int>qx;
vector<int>px[1001];
stack<int>st;
int dist[N], start[N];
bool tuopu()
{
    while(!qx.empty())qx.pop();
    while(!st.empty())st.pop();
    for(int i=1; i<=n; i++)
        if(!in[i])qx.push(i);

    memset(dist,0,sizeof(dist));
    while(!qx.empty())
    {
        int u=qx.front();
        qx.pop();
        st.push(u);
        for(int i=head[u]; i!=-1; i=p[i].next)
        {
            int v=p[i].v;
            in[v]--;
            if(!in[v])qx.push(v);
            dist[v]=max(dist[u]+p[i].w,dist[v]);
            maxt=max(maxt,dist[v]);
        }
    }
    return st.size()==n;
}
void valuepath()
{
    fill(start,start+n+1,maxt);
    while(!st.empty())
    {
        int u=st.top();
        st.pop();
        for(int i=head[u]; i!=-1; i=p[i].next)
        {
            int v=p[i].v;
            start[u]=min(start[u],start[v]-p[i].w);
        }
    }
    for(int i=1; i<=n; i++)
    {
        for(int j=head[i]; j!=-1; j=p[j].next)
        {
            int u=p[j].v;
            edge[i][u]=dist[i];
            last[i][u]=start[u]-p[j].w;
            if(start[u]-p[j].w==dist[i])
            {
                px[i].push_back(u);
            }
        }
    }
    return ;
}
void init()
{
    memset(head,-1,sizeof(head));
    memset(in,0,sizeof(in));
    for(int i=0; i<=n; i++)px[i].clear();
    cnt=0;
}
int ans[N];
void dfs(int u,int pos)
{
    ans[pos]=u;
    int flag=0;
    for(int i=0;i<px[u].size();i++)
    {
        int v=px[u][i];
        dfs(v,pos+1);
        flag=1;
    }
    if(!flag&&start[u]==maxt)
    {
        printf("%d",ans[0]);
        for(int i=1;i<=pos;i++)
            printf("->%d",ans[i]);
        printf("\n");
        return ;
    }
}

int main()
{
    scanf("%d %d", &n, &m);
    init();
    for(int i=0; i<m; i++)
    {
        scanf("%d %d %d", &q[i].u,&q[i].v,&q[i].w);
        in[q[i].v]++;
    }
    int d[N], cnt=0;
    for(int i=1;i<=n;i++)
        if(in[i]==0) d[cnt++]=i;
    sort(q,q+m);
    for(int i=0; i<m; i++)
    {
        int x=q[i].u,y=q[i].v,z=q[i].w;
        add(x,y,z);
    }

    int flag=tuopu();
    if(!flag)puts("NO");
    else puts("YES");

    if(flag)
        valuepath();
    int k;
    scanf("%d", &k);
    while(k--)
    {
        int x, y;
        scanf("%d %d", &x, &y);
        if(!flag)continue;
        printf("%d %d\n",edge[x][y],last[x][y]);
    }
    if(!flag)return 0;
    printf("%d\n",maxt);
    for(int i=0;i<cnt;i++) 
     dfs(d[i],0);

    return 0;
}

超时代码。。正向记忆化dfs

#include<bits/stdc++.h>
#include<stdlib.h>
using namespace std;
typedef long long LL;
const LL mod = 1e9+7;
const int N = 1000+10;
typedef long long LL;
struct node
{
    int u, v, w, next;
    bool operator <(const node& A)const
    {
        if(u!=A.u)return u<A.u;
        return v>A.v;
    }
}p[N*N], q[N*N];
int head[2*N];
int cnt;

void add(int x,int y,int z)
{
    p[cnt].u=x,p[cnt].v=y,p[cnt].next=head[x],p[cnt].w=z;
    head[x]=cnt++;
    return ;
}
bool in[N];
int vis[N];
int first[N], last[N][N], w[N][N], edge[N][N];
int tmp, flag;
int e_nd, maxt=0;
void init()
{
    memset(head,-1,sizeof(head));
    memset(edge,-1,sizeof(edge));
    cnt=0;
}
void judge(int u,int s)
{
    if(in[u]||flag)return ;
    if(s<=vis[u]&&s!=0)return ;
    vis[u]=max(vis[u],s);
    in[u]=1,maxt=max(s,maxt);
    for(int i=head[u];i!=-1;i=p[i].next)
    {
        int v=p[i].v;
        if(in[v])
        {
            flag=1;
            return ;
        }
        edge[u][v]=max(s,edge[u][v]);
        judge(v,s+p[i].w);
    }
    in[u]=0;
    return ;
}
int geted[1010];
void dfs(int u)
{
    int O=0;
    for(int i=head[u];i!=-1;i=p[i].next)
    {
        int v=p[i].v;
        if(geted[v]==-1) dfs(v);
        last[u][v]=geted[v]-p[i].w;
        if(geted[u]==-1||geted[u]>last[u][v])geted[u]=last[u][v];
        O=1;
    }
    if(!O)geted[u]=maxt;
    return ;
}
//int pos;
int dist[1010];
void travel(int u,int pos,int sum)
{
    dist[pos]=u;
    int O=0;
    for(int i=head[u];i!=-1;i=p[i].next)
    {
        int v=p[i].v;
        if(sum==last[u][v])  travel(v,pos+1,sum+p[i].w);
        O=1;
    }
    if(!O)
    {
        printf("%d",dist[0]);
        for(int i=1;i<=pos;i++)printf("->%d",dist[i]);
        printf("\n");
        return ;
    }
    return ;
}

int main()
{
    int n, m;
    scanf("%d %d", &n, &m);
    init();
    memset(in,0,sizeof(in));
    for(int i=0;i<m;i++)
    {
        scanf("%d %d %d", &q[i].u,&q[i].v,&q[i].w);
        in[q[i].v]=1;
    }
    sort(q,q+m);
    for(int i=0;i<m;i++)
    {
        int x=q[i].u,y=q[i].v,z=q[i].w;
        add(x,y,z);
        w[x][y]=z;
    }
    int dx[N], k=0;
    for(int i=1;i<=n;i++)
    {
        if(!in[i])dx[k++]=i;//出现环的话找不到根节点,可能有多个根节点
    }
    tmp=0;
    memset(in,0,sizeof(in));
    memset(last,-1,sizeof(last));
    flag=0;

    if(k==0)flag=1;
    else
    {
        memset(vis,0,sizeof(vis));
        for(int i=0;i<k;i++)
        {
            if(!flag)judge(dx[i],0);
        }
    }

    if(flag)puts("NO");
    else puts("YES");


    if(!flag)
    {
        memset(geted,-1,sizeof(geted));
        for(int i=0;i<k;i++)dfs(dx[i]);
    }
    int k1;
    scanf("%d", &k1);
    while(k1--)
    {
        int x, y;
        scanf("%d %d", &x, &y);
        if(flag)continue;
        printf("%d %d\n",edge[x][y],last[x][y]);
    }
    if(!flag)
    {
        printf("%d\n",maxt);
        for(int i=0;i<k;i++)travel(dx[i],0,0);
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值