关键路径
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;
}