题意:给定n个点,m条边,起点为0,终点为1。对于路径上除终点外的每一个点,其到终点1的最短路径上都有一个标志,问是否能在绕开标志的情况下找到一条从0到1的路径,存在的话打印路径。
大致思路是将有标志的边删掉,然后dfs看0到1是否连通。
问题的重点在于如何快速优雅地找到有标志的边。
从题意中可以看到,所有的标志都是到1的最短路上的标志,所以可以把1做为源点,跑最短路。dfs的时候判断一下边的两个端点u和v是否满足dist[u]=dist[v]+weight[u][v],若满足,则该边不通。
没什么坑点,直接贴代码
#include <bits/stdc++.h>
#define N 100010
#define LL long long
#define INF 0x3f3f3f3f3f
using namespace std;
typedef pair<LL,int>pa;
vector<pa>edge[N];
LL dis[N];
int path[N],vis[N],flag=0;
void dijkstra(int x){
memset(dis,INF, sizeof(dis));
priority_queue<pa,vector<pa>,greater<pa> >qu;
qu.push(pa(0,x));
dis[x]=0;
while(!qu.empty()){
pa u=qu.top();
qu.pop();
for(int i=0;i<edge[u.second].size();i++){
int v=edge[u.second][i].second;
LL w=edge[u.second][i].first;
if(w+u.first<dis[v]){
dis[v]=w+u.first;
qu.push(pa(dis[v],v));
}
}
}
}
void dfs(int x){
if(x==1){
flag=1;
return;
}
for(int i=0;i<edge[x].size();i++){
int v=edge[x][i].second;
if(dis[x]==dis[v]+edge[x][i].first)
continue;
if(!vis[v]){
vis[v]=1;
path[x]=v;
dfs(v);
}
if(flag)//如果找到从0到1的路径即退出dfs
return;
}
}
int main(){
int n,m;
scanf("%d%d",&n,&m);
int u,v;
LL w;
for(int i=0;i<m;i++){
scanf("%d%d%lld",&u,&v,&w);
edge[u].push_back(pa(w,v));
edge[v].push_back(pa(w,u));
}
dijkstra(1);
vis[0]=1;
memset(path,-1, sizeof(path));
dfs(0);
if(flag){
vector<int>ans;
int x=0;
while(x!=-1){
ans.push_back(x);
x=path[x];
}
printf("%d",ans.size());
for(int i=0;i<ans.size();i++)
printf(" %d",ans[i]);
printf("\n");
} else
printf("impossible\n");
return 0;
}
懒惰如我竟然开始写题解。其实只是因为很久没写最短路,mark一下dijkstra的板子233333。