Longest Path
题目大意
这个是一个有向无环图,

然后求最长的那个路径,
错误解法
void solve() {
int n,m,rec=INT_MIN;cin>>n>>m;
vector<int>dp(n+1);
while(m--){
int x,y;cin>>x>>y;
dp[y]=max(dp[y],dp[x]+1);
rec=max(dp[y],rec);
}
cout<<rec<<endl;
似乎把问题想的太简单了
错误原因
3 2
2 3
1 2
1->2->3,应该是3
但是你的写法会让答案是1,但是正确答案是2
因为你在处理2的时候,2是0,但是后面会跟3连,这个时候2又变成1了,但是1没有被记录进去
究其原因就是,题目不一定都是按照拓扑序拍好的,
什么叫拓扑序?拓扑序(Topological Order),简单来说,就是“按先后依赖关系排好的一条直线顺序”。
有向无环图才有拓扑序,是才有,不是一定有
题目给的例子你都能过,因为题目的例子都非常阴间的按照拓扑序排好的
正确解法1 DFS
const int MAXN = 100005;
vector<int> adj[MAXN];
int dp[MAXN]; // dp[u] 表示从 u 出发的最长路径
int dfs(int u){
if(dp[u]!=-1)return dp[u];
int rec=0;
for(int v:adj[u]){
rec=max(rec,dfs(v)+1);
}
return dp[u]=rec;
}
void solve(){
int n,m;
cin>>n>>m;
while(m--){
int x,y;
cin>>x>>y;
adj[x].pb(y);
}
memset(dp,-1,sizeof(dp));
int ans=0;
for(int i=1;i<=n;i++){
ans=max(ans,dfs(i));
}
cout<<ans<<endl;
}
解释
枚举每一个点,看从哪一个点出发的距离是最大的
正确解法2 拓扑序+dp
//拓扑排序 + DP(Kahn 算法)
void solve2(){
int n,m;cin>>n>>m;
vector<int>dp(n+1);
vector<int>in_degree(n+1);
vector<vector<int>>adj(n+1);
queue<int>q;
int ans=0;
while(m--){
int x,y;cin>>x>>y;
adj[x].pb(y);
in_degree[y]++;//记录它的前驱,如果没有前驱就是直接进入queue
/*
这个就对应了这个例子
2 3
1 2
只有当2没有前驱的时候,才可以入队列,
才可以有dp[3]=max(dp[3],dp[2]+1)
*/
}
for(int i=1;i<=n;i++){
if(in_degree[i]==0){
q.push(i);
}
}
while(!q.empty()){
int kk=q.front();
ans=max(ans,dp[kk]);//记录全局的最大值
q.pop();
for(int v:adj[kk]){
dp[v]=max(dp[v],dp[kk]+1);
in_degree[v]--;//如果这条边没来,它的度就为0了,说明没有前驱了,就可以进入队列了
if(in_degree[v]==0)q.push(v);
}
}
cout<<ans<<endl;
}
解释,就如上面那个例子,只有2没有前驱的时候,才可以方向的进行
dp[3]=max(dp[3],dp[2]+1),我们维护一个队列,这个队列记录的就是那些没有前驱的点

浙公网安备 33010602011771号