洛谷2149(最长公共路径)
RocketTurtle · · 题解
这道题是一道图论+dp题,也是我目前做到的第二道图论+dp题QWQ。但是我一开始没有想到要外跑dp,所以两次尝试案例答案都错误。然后我就看了@我不是纸张啊这位大佬的博客emmmm....
以下是我的代码的:
inline void dijkstra(int start){
++ans;
priority_queue<pair<int,int> >q;
memset(vis,0,sizeof(vis));
fp(i,1,n) dis[i][ans]=0x3f3f3f3f;dis[start][ans]=0;
dis[start][ans]=0;q.push(make_pair(0,start));
while(!q.empty()){
int temp=q.top().second;q.pop();
if(vis[temp]) continue;
vis[temp]=1;
for(int i=head[temp];i;i=edge[i].prev){
int to=edge[i].to;
if(dis[to][ans]>dis[temp][ans]+edge[i].w){
dis[to][ans]=dis[temp][ans]+edge[i].w;
q.push(make_pair(-dis[to][ans],to));
}
}
}
}
这个是dij板子,就不用多说了。
inline void csh(){
dijkstra(x1);dijkstra(y11);dijkstra(x2);dijkstra(y22);
}
两个人的起点和终点分别跑一次最短路,即总共四次。
接下来就是如何处理满足条件的边集合了: 1:首先符合条件的边肯定是属于最短路径中的。所以我们可以遍历每一条边 即这条边的权值+正向dis+反向dis即是整条路径的长度,若其值等于最短路径的值,即把它加入到新图中。
2:同时每条边要去判断是不是属于另一个人的最短路径,若是,代码中就将此边标记为1.
下面就贴我的ac代码了
#include<bits/stdc++.h>
using namespace std;
inline int read(){
char c=getchar();int x=0,f=1;
while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x*f;
}
inline void out(int a){
if(a<0)
{
putchar('-');
a=-a;
}
if(a>9) out(a/10);
putchar(a%10+'0');
}
int n,m,x1,y11,x2,y22;
struct Edge{
int from,to,prev,flag,w;
}edge[1000000],e[1000000];
int cnt,head[2000];
inline void add(int x,int y,int w){
edge[++cnt].to=y;
edge[cnt].from=x;
edge[cnt].w=w;
edge[cnt].prev=head[x];
head[x]=cnt;
}
int he[2000],ans,h;
inline void adds(int x,int y,int w){
e[++h].to=y;
e[h].from=x;
e[h].w=w;
e[h].prev=he[x];
he[x]=h;
}
#define fp(i,w,n) for(int i=w;i<=n;i++)
inline void start(){
n=read(),m=read();
x1=read(),y11=read(),x2=read(),y22=read();
fp(i,1,m){
int x,y,w;x=read(),y=read(),w=read();
add(x,y,w);add(y,x,w);
}
}
int vis[2000],dis[2000][5];
inline void dijkstra(int start){
++ans;
priority_queue<pair<int,int> >q;
memset(vis,0,sizeof(vis));
fp(i,1,n) dis[i][ans]=0x3f3f3f3f;dis[start][ans]=0;
dis[start][ans]=0;q.push(make_pair(0,start));
while(!q.empty()){
int temp=q.top().second;q.pop();
if(vis[temp]) continue;
vis[temp]=1;
for(int i=head[temp];i;i=edge[i].prev){
int to=edge[i].to;
if(dis[to][ans]>dis[temp][ans]+edge[i].w){
dis[to][ans]=dis[temp][ans]+edge[i].w;
q.push(make_pair(-dis[to][ans],to));
}
}
}
}
inline void csh(){
dijkstra(x1);dijkstra(y11);dijkstra(x2);dijkstra(y22);
}
int arrive[2000],dp[2000];
inline void solve(){
csh();
fp(i,1,cnt){
int from=edge[i].from,to=edge[i].to;
if(dis[from][1]+edge[i].w+dis[to][2]==dis[y11][1]){
adds(from,to,edge[i].w);
if(dis[from][3]+edge[i].w+dis[to][4]==dis[y22][3]||dis[from][4]+edge[i].w+dis[to][3]==dis[y22][3]){
e[h].flag=1;
}
arrive[to]++;
}
}
queue<int> q;
q.push(x1);
while(!q.empty()){
int temp=q.front();q.pop();
for(int i=he[temp];i;i=e[i].prev){
int to=e[i].to;arrive[to]--;
dp[to]=max(dp[to],dp[temp]+e[i].w*e[i].flag);
if(!arrive[to]) q.push(to);
}
}
out(dp[y11]),putchar('\n');
}
int main(){
start();
solve();
return 0;
}
以下是大佬@我不是纸张啊 的代码中我没看懂的部分
if(to[b[i].to]==0){
q.push(b[i].to);
dp[b[i].to]=max(dp[b[i].to],dp[l]+b[i].w*b[i].ok);
}
以下是大佬的解释:
怎么dp呢?我们考虑在拓扑排序中dp,如果一个点x没有出边了才去管他,他的值就是连他的那个点的dp值,如果是两个最短路的公共路径,就还要加上这条路的权值,否则就不用.
但是我认为这样会漏掉很多数组滚动的可能性,可能大佬的思想比较深厚吧。