Important Roads
Problem Description
The city where Georgie lives has n junctions some of which are connected by bidirectional roads.
Every day Georgie drives from his home to work and back. But the roads in the city where Georgie lives are very bad, so they are very often closed for repair. Georgie noticed that when some roads are closed he still can get from home to work in the same time as if all roads were available.
But there are such roads that if they are closed for repair the time Georgie needs to get from home to work increases, and sometimes Georgie even cannot get to work by a car any more. Georgie calls such roads important.
Help Georgie to find all important roads in the city.
Input
The first line of the input file contains n and m — the number of junctions and roads in the city where Georgie lives, respectively (2 ≤ n ≤ 20 000, 1 ≤ m ≤ 100 000). Georgie lives at the junction 1 and works at the junction n.
The following m lines contain information about roads. Each road is specified by the junctions it connects and the time Georgie needs to drive along it. The time to drive along the road is positive and doesn’t exceed 100 000. There can be several roads between a pair of junctions, but no road connects a junction to itself. It is guaranteed that if all roads are available, Georgie can get from home to work.
Output
Output l — the number of important roads — at the first line of the output file. The second line must contain l numbers, the numbers of important roads. Roads are numbered from 1 to m as they are given in the input file.
Sample Input
6 7
1 2 1
2 3 1
2 5 3
1 3 2
3 5 1
2 4 1
5 6 2
Sample Output
2
5 7
原题地址:http://acdream.info/problem?pid=1415
思路:
分三步操作:
1、求每个点到源点的最短距离d。用优先队列优化的Dijkstra算法。
2、根据上一步得出的结果进一步求出所有从源点到终点的最短路包含的边。从终点开始进行普通bfs,对于边(u,v),只要满足d[v] + edge.dis == d[u],那么这条边就是上述要求的边。
3、用tarjan算法思想求出所有桥。
补充:tarjan简述
先看求桥的dfs代码:
int low[MAXN],dfn[MAXN],Index;
int ans[MAXM],cnt;
void dfs(int u,int preID) { //这里的 preID不是一般代码中的父亲结点id,而是上一次搜索过的边的id。原因是题目中说了会有重边-_-。这里被坑了好久。
low[u]=dfn[u]=++Index;
for(int e=g2.head[u];e!=-1;e=g2.edge[e].next) {
int v=g2.edge[e].to, id=g2.edge[e].id;
if(id==preID) continue;
if(dfn[v]==0) dfs(v,id);
low[u]=min(low[u],low[v]);
if(low[v]>dfn[u]) {
ans[cnt++]=g2.edge[e].id;
}
}
}
dfn[u]记录节点u在DFS过程中被遍历到的次序号,low[u]记录节点u或u的子树通过非父子边追溯到最早的祖先节点(即DFS次序号最小)。
tarjan算法不止可以用在这里求桥,还有其他很多应用。
代码:
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
using namespace std;
const int MAXN = 20005;//点数的最大值
const int MAXM = 100005*2;//边数的最大值
const int INF = (1<<31)-1;
struct MAP
{
struct Edge
{
int to,next,dis,id;
bool cut;
} edge[MAXM];
int tot;
int head[MAXN];
void init()
{
tot = 0;
memset(head,-1,sizeof(head));
}
void addedge(int u,int v,int dis,int id)
{
edge[tot].to=v;
edge[tot].dis=dis;
edge[tot].next=head[u];
edge[tot].id=id;
head[u]=tot++;
}
} g1,g2;
int d[MAXN];
bool vis[MAXN];
struct Node
{
int u,dis;
Node(int u,int d):u(u),dis(d) {}
};
bool operator < (Node a,Node b)
{
return a.dis > b.dis;
}
void createG2(int n)
{
//求最短路
memset(vis,0,sizeof(vis));
priority_queue<Node> que;
for(int i=0; i<=n; i++) d[i]=INF;
d[1]=0;
que.push(Node(1,0));
while(!que.empty())
{
Node tmp = que.top();
que.pop();
int u=tmp.u;
if(vis[u]) continue;
vis[u]=true;
for(int e=g1.head[u]; e!=-1; e=g1.edge[e].next)
{
int v=g1.edge[e].to,dis=g1.edge[e].dis;
if(vis[v]) continue;
if(d[u]+dis<d[v])
{
d[v]=d[u]+dis;
que.push(Node(v,d[v]));
}
}
}
//建立G2
g2.init();
memset(vis,0,sizeof(vis));
queue<int> q;
q.push(n);
while(!q.empty())
{
int u=q.front();
q.pop();
if(vis[u]) continue;
vis[u]=true;
for(int e=g1.head[u]; e!=-1; e=g1.edge[e].next)
{
int v=g1.edge[e].to, dis=g1.edge[e].dis, id=g1.edge[e].id;
if(d[v]+dis==d[u])
{
q.push(v);
g2.addedge(u,v,0,id);
g2.addedge(v,u,0,id);
}
}
}
}
int low[MAXN],dfn[MAXN],Index;
int ans[MAXM],cnt;
void dfs(int u,int preID) {
low[u]=dfn[u]=++Index;
for(int e=g2.head[u];e!=-1;e=g2.edge[e].next) {
int v=g2.edge[e].to, id=g2.edge[e].id;
if(id==preID) continue;
if(dfn[v]==0) dfs(v,id);
low[u]=min(low[u],low[v]);
if(low[v]>dfn[u]) {
ans[cnt++]=g2.edge[e].id;
}
}
}
int main()
{
int n,m,u,v,dis;
scanf("%d%d",&n,&m);
g1.init();
g2.init();
for(int i=0; i<m; i++)
{
scanf("%d%d%d",&u,&v,&dis);
g1.addedge(u,v,dis,i+1);
g1.addedge(v,u,dis,i+1);
}
createG2(n);
memset(low,0,sizeof(low));
memset(dfn,0,sizeof(dfn));
Index=0;
cnt=0;
dfs(1,-1);
sort(ans,ans+cnt);
printf("%d\n",cnt);
if(cnt>0)
{
for(int i=0; i<cnt; i++)
{
if(i==0) printf("%d",ans[i]);
else printf(" %d",ans[i]);
}
puts("");
}
return 0;
}