您的位置:首页 > 其它

URAL 1934 最短路变形

2015-07-29 11:07 369 查看
DES:给出起点和终点。给出所有小岛的编号。所有路径的起始点。和遇到怪物的概率。要求在最短路的条件下维护遇见怪物的概率最小的路径。就是用 SPFA算法。每条路的权值设为1。最短路即为途径的岛数最少。同时要用pre数组维护每个点的前驱。最后递归输出所走路径。把p变为不遇见怪物的概率, 即为维护p最大。就是把原来的SPFA里的判断多加一条,如果权值相等判断概率,选择概率大的一条。

注意。这是无向图。本来觉得没有影响。很幸福的WA了。确实是。给你a->b的,就代表可以从b->a。而不是简单的可以往返。

不知道用邻接表和邻接矩阵时间差大不大。这里用了邻接表

#include<stdio.h>
#include<iostream>
#include<string.h>
using namespace std;
#include<queue>
#define N 100010
#define inf 0x1f1f1f1f

int low
; //存储源点到每个顶点的最短距离值
bool in_que
; //标记一个点是否已在队列中
int cnt
; //记录每个点的入队次数,来判断是否出现负环
int pre
; // 记录每个点的前驱。即记录源点到每个点的最短路径本身。
int head
; //邻接矩阵的表头节点
double p
; //存储最短路的情况下。到每个点的p最大。
int n, m;
int h;
bool flag = true;

struct Edge
{
int v, w, next;
double p;
}edge[N<<1];

void addEdge(int a, int b, double c)
{
edge[h].v = b;
edge[h].w = 1;
edge[h].p = c;
edge[h].next = head[a];
head[a] = h++;
}

void spfa(int s)
{
for (int i=0; i<=n; ++i)
{
p[i] = 0;
low[i] = inf;
}
memset(pre, -1, sizeof(pre));
memset(in_que, 0, sizeof(in_que));
queue<int>q;
in_que[s] = 1;
low[s] = 1;
p[s] = 1; //没有怪物
q.push(s);

while(!q.empty())
{
int x = q.front();
q.pop();
in_que[x] = 0;
for (int i=head[x]; i!=-1; i=edge[i].next)
{
int v = edge[i].v;
if (low[v] > low[x]+1)
{
low[v] = low[x] + 1;
p[v] = p[x]*edge[i].p;
pre[v] = x;
if (!in_que[v])
{
in_que[v] = 1;
q.push(v);
}
}
else if (low[v] == low[x] + 1)
{
if (p[v] < p[x]*edge[i].p)
{
p[v] = p[x]*edge[i].p;
pre[v] = x;
if (!in_que[v])
{
in_que[v] = 1;
q.push(v);
}
}
}
}
}
return;
}

void output(int r)
{
if (pre[r] != -1) output(pre[r]);
if (flag) flag = false;
else putchar(' ');
printf("%d", r);
}

int main()
{
int s, t;
int a, b;
double c;
while(~scanf("%d%d", &n, &m))
{
scanf("%d%d", &s, &t);
h = 0;
memset(head, -1, sizeof(head));
for (int i=0; i<m; ++i)
{
scanf("%d%d%lf", &a, &b, &c);
c = (1-c/100);
addEdge(a, b, c);
addEdge(b, a, c);
}
spfa(s);
printf("%d %.6lf\n", low[t], 1-p[t]);
flag = true;
output(t);
puts("");
}
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: