和hdu 的1595很像,但是多的是出现重边,即无法用邻接矩阵这种方式存图。而在邻接表记录边是,每次删边的操作,其实就是在松弛过程中遍历到需要删除的边时,跳过即可。那么就可以加一个数组记录边,然后使用时判断是不是要删边就好了。
关于edge数组,就是拿来记录最短路上的指向到达点(e【i】.to)的那条边的编号的(也就是那条边)。因为每次操作时删去的必然是最短路上的边,而因为有重边的存在(也有可能没有,,根据给出的图来定),删去的当前的最短路上的边并不影响其他重边的存在。
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
using namespace std;
#define N 1005
const int inf = 1 << 28;
struct node{
int to, nxt, w;
bool used;
}e[N*N];
int dis[N];
int head[N];
int pre[N];
int n, m;
int cnt;
int edge[N];
void init()
{
memset(head, -1, sizeof(head));
cnt = 0;
}
void add( int u, int v, int w )
{
e[cnt].to = v;
e[cnt].w = w;
e[cnt].used = 1;
e[cnt].nxt = head[u];
head[u] = cnt++;
}
void spfa(int f)
{
queue<int> q;
while( !q.empty() )
q.pop();
q.push(1);
for( int i = 1; i <= n; i++ )
dis[i] = inf;
dis[1] = 0;
while( !q.empty() )
{
int now = q.front();
q.pop();
for( int i = head[now]; ~i; i = e[i].nxt )
if( e[i].used )
{
int to = e[i].to;
if( dis[to] > dis[now] + e[i].w )
{
dis[to] = dis[now] + e[i].w;
q.push(to);
if( f )
{
pre[to] = now; //记录前向边,松弛完所有边之后,从终点往前找就是最短路上的点
//(注:当最短路不止一条时这种记录的只是其中某条最短路,怎么记录全部的最短路??。。)
edge[e[i].to] = i;//到达to这个点的边,标记
}
}
}
}
}
int main()
{
int tot;
scanf("%d", &tot);
while(tot--)
{
scanf("%d %d", &n, &m);
init();
int u, v, w;
for( int i = 1; i <= m; i++ )
{
scanf("%d%d%d", &u, &v, &w);
add(u, v, w);
add(v, u, w);
}
spfa(1);
if( dis[n] == inf )
{
printf("-1\n");
continue;
}
//printf("feargzs\n");
int ans = 0;
for( int i = n; i != 0; i = pre[i] )
{
e[edge[i]].used = 0;//到i这个点在松弛过程中跳过
spfa(0);
if( dis[n] != inf )
ans = max(ans, dis[n]);
else
{
ans = -1;
break;
}
e[edge[i]].used = 1; //复原
}
printf("%d\n", ans);
}
return 0;
}
![得意](http://static.blog.csdn.net/xheditor/xheditor_emot/default/proud.gif)