题目分析
读题可知,这是一道经典的拓扑排序模板题
要解决拓扑排序的问题,第一步很重要:建图
struct edge{
int u;//起点
int v;//终点
}; //存储边的 起点与终点
vector<int>vec[10000+10]; // vec[a][b]=c表示顶点a的第b条边是 c号边(从0开始算)
vector<edge>s;//存储每个边的信息(要进行一次排序)
int val[10000+10]; //完成每个杂务所需要的时间
int n;//杂务的数目,即结点数
int f[10000+10];//f[i]表示完成前i个杂务所需要的最短时间(具有不减性)
int ru[10000+10];//结点的入度数,入度表示该结点为被指向的结点
bool cmp(edge x,edge y)
{//给输入的边进行排序,先按照终点,如果终点相同则按照起点
if(x.v==y.v)
return x.u<y.u;
else
return x.v<y.v;
}
cin>>n;
for(int i=1;i<=n;i++)
{
int u,v;
cin>>v>>val[i];
while(cin>>u&&u!=0)
{
edge e; e.u=u; e.v=v;
s.push_back(e); //将该 边 压入s数组
ru[v]++; //入度+1
}
}
sort(s.begin(),s.end(),cmp);
for(int i=0;i<s.size();i++)
vec[s[i].u].push_back(i); //依据起点来存储
第二步:入度为0的点进入队列
queue<int>q;
for(int i=1;i<=n;i++)
if(ru[i]==0)
q.push(i),f[i] = val[i] ; //默认杂务1没有前驱结点
第三步:拓扑排序,队列中的点依次出队列
int fmax = f[1];//记录最大时间
while(!q.empty())
{//拓扑排序
int now = q.front();q.pop();
for(int i=0;i<vec[now].size();i++)
{
int num = vec[now][i]; // 边的编号
int next_node = s[num].v;//临接的下一个点
f[next_node] = max(f[next_node],f[now]+val[next_node]);//递推公式,当前点的所需时间等于前面所有指向该点的 前驱结点的时间+当前结点的花费时间
ru[next_node]--; //入度-1
if(ru[next_node]==0)//如果当前结点入度为0,则入队列
q.push(next_node);
}
fmax = max(fmax,f[now]);
}
AC代码
/*
Author:snnu_lgw
Date:2020/7/5
*/
#include<vector>
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
struct edge{
int u;//起点
int v;//终点
}; //存储边的 起点与终点
vector<int>vec[10000+10]; // vec[a][b]=c表示顶点a的第b条边是 c号边(从0开始算)
vector<edge>s;//存储每个边的信息(要进行一次排序)
int val[10000+10]; //完成每个杂务所需要的时间
int n;//杂务的数目,即结点数
int f[10000+10];//f[i]表示完成前i个杂务所需要的最短时间(具有不减性)
int ru[10000+10];//结点的入度数,入度表示该结点为被指向的结点
bool cmp(edge x,edge y)
{//给输入的边进行排序,先按照终点,如果终点相同则按照起点
if(x.v==y.v)
return x.u<y.u;
else
return x.v<y.v;
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
int u,v;
cin>>v>>val[i];
while(cin>>u&&u!=0)
{
edge e; e.u=u; e.v=v;
s.push_back(e);
ru[v]++;
}
}
sort(s.begin(),s.end(),cmp);
for(int i=0;i<s.size();i++)
vec[s[i].u].push_back(i); //依据起点来存储
int fmax = f[1];//记录最大时间
queue<int>q;
for(int i=1;i<=n;i++)
if(ru[i]==0)
q.push(i),f[i] = val[i] ; //默认杂务1没有前驱结点
while(!q.empty())
{//拓扑排序
int now = q.front();q.pop();
for(int i=0;i<vec[now].size();i++)
{
int num = vec[now][i]; // 边的编号
int next_node = s[num].v;//临接的下一个点
f[next_node] = max(f[next_node],f[now]+val[next_node]);//递推公式,当前点的所需时间等于前面所有指向该点的 前驱结点的时间+当前结点的花费时间
ru[next_node]--; //入度-1
if(ru[next_node]==0)//如果当前结点入度为0,则入队列
q.push(next_node);
}
fmax = max(fmax,f[now]);
}
cout<<fmax;
return 0;
}