题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3499
题意:
有一个有向图,你要从特定的城市A飞到城市B去.给你这个图的所有边(航班)信息.但是你手上有一张卡,可以使得某一趟航班的价格减半.现在的问题是你从A到B的最小费用是多少?
分析:
首先要知道这条如果让一条原本是最短路径(假设总距离为x)上最长的边变成半价,最终求得的解不一定是最优的。因为假如现在有另外一条路径,假设该路径距离为x+1。且这条路径上只有5条边,4条长为1的边,但是1条长为x-3的边。如果我们让这条路径的x-3边变成半价是不是能得到更好的结果?
明显必须从m条边中枚举那条半价的航班.假设这条半价的航班是i->j的.那么我们必须知道从A到i的最短距离和从j到B的最短距离. 从A到i的最短距离可以通过求A的单源最短路径即可.从j(j有可能是任意点)到B的最短距离必须建立原图的反向图,然后求B到其他所有点的单源最短路径.(想想是不是)
原题输入数据很多,需要用邻接表的dijkstra算法且距离要用long long保存
结构体封装代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
#include<map>
using namespace std;
const long long INF = 1e17;
const int maxn = 100005;
const int maxm = 500005;
int n, m;
map<string, int> mp;
struct Edge
{
int form, to, next;
long long dist;
Edge(){}
Edge(int _form, int _to, long long _dist):form(_form), to(_to), dist(_dist){}
Edge(int _form, int _to, long long _dist, int _next):form(_form), to(_to), dist(_dist), next(_next){}
}edge[maxm];
struct HeapNode
{
long long d;
int u;
HeapNode(){}
HeapNode(int _u, long long _d):u(_u), d(_d){};
bool operator < (const HeapNode &other) const
{
return d > other.d;
}
};
struct Dijkstra
{
int n, m, head[maxm];
Edge edge[maxm];
long long dis[maxn];
void init()
{
m = 0;
memset(head, -1, sizeof(head));
}
void add_edge(int from, int to, long long dist)
{
edge[m] = Edge(from, to, dist, head[from]);
head[from] = m++;
}
void dijkstra(int s)
{
priority_queue<HeapNode> q;
for(int i = 0; i < n; i++)
dis[i] = i == s ? 0 : INF;
q.push(HeapNode(s, dis[s]));
while(!q.empty())
{
HeapNode x = q.top();
q.pop();
int u = x.u;
for(int i = head[u]; i != -1; i = edge[i].next)
{
if(dis[edge[i].to] > dis[u] + edge[i].dist)
{
dis[edge[i].to] = dis[u] + edge[i].dist;
q.push(HeapNode(edge[i].to, dis[edge[i].to]));
}
}
}
}
}dj1, dj2;
int getid(string s)
{
if(mp.find(s) == mp.end())
mp[s] = n++;
return mp[s];
}
int main()
{
int u, v;
long long w;
while(scanf("%d%d", &n, &m) != EOF)
{
n = 0;
mp.clear();
string s1, s2;
dj1.init();dj2.init();
for(int i = 0; i < m ; i++)
{
cin >> s1 >> s2 >> w;
u = getid(s1);
v = getid(s2);
dj1.add_edge(u, v, w);
dj2.add_edge(v, u, w);
edge[i] = Edge(u, v, w);
}
cin >> s1 >> s2;
int st = getid(s1), ed = getid(s2);
dj1.n = dj2.n = n;
dj1.dijkstra(st), dj2.dijkstra(ed);
if(dj1.dis[ed] == INF)
{
printf("-1\n");
continue;
}
long long ans = INF;
for(int i = 0; i < m; i++)
{
int u = edge[i].form, v = edge[i].to;
long long w = edge[i].dist;
if(ans > dj1.dis[u] + dj2.dis[v] + w / 2)
ans = dj1.dis[u] + dj2.dis[v] + w / 2;
}
printf("%I64d\n", ans);
}
return 0;
}
二维数组代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
#include<map>
using namespace std;
const int maxm = 500005;
const int maxn = 100005;
const long long INF = 1e17;
struct Edge
{
int u, v, next;
long long w;
Edge(){}
Edge(int _u, int _v, long long _w, int _next):u(_u), v(_v), w(_w), next(_next){}
}edge[2][maxm];
struct HeapNode
{
long long d;
int u;
HeapNode(int _u, long long _d):u(_u), d(_d){}
bool operator < (const HeapNode &other)const
{
return d > other.d;
}
};
int n, m, head[2][maxn];
long long dis[2][maxn];
map<string, int> mp;
int getid(string s)
{
if(mp.find(s) == mp.end())
mp[s] = n++;
return mp[s];
}
void Dijkstra(int flag, int s)
{
for(int i = 0; i < n; i++)
dis[flag][i] = INF;
dis[flag][s] = 0;
priority_queue<HeapNode> q;
q.push(HeapNode(s, dis[flag][s]));
while(!q.empty())
{
HeapNode now = q.top();
q.pop();
for(int i = head[flag][now.u]; i != -1; i = edge[flag][i].next)
{
int to = edge[flag][i].v;
if(dis[flag][to] > dis[flag][now.u] + edge[flag][i].w)
{
dis[flag][to] = dis[flag][now.u] + edge[flag][i].w;
q.push(HeapNode(to, dis[flag][to]));
}
}
}
}
int main()
{
while(scanf("%d%d", &n, &m) != EOF)
{
n = 0;
string s1, s2;
mp.clear();
memset(head, -1, sizeof(head));
memset(dis, 63, sizeof(dis));
for(int i = 0; i < m; i++)
{
long long w;
cin >> s1 >> s2 >> w;
int u = getid(s1), v = getid(s2);
edge[0][i] = Edge(u, v, w, head[0][u]);
head[0][u] = i;
edge[1][i] = Edge(v, u, w, head[1][v]);
head[1][v] = i;
}
cin >> s1 >> s2;
int st = getid(s1), ed = getid(s2);
Dijkstra(0, st);
Dijkstra(1, ed);
if(dis[0][ed] == INF)
{
printf("-1\n");
continue;
}
long long ans = INF;
for(int i = 0; i < m; i++)
{
int u = edge[0][i].u, v = edge[0][i].v;
long long dist = edge[0][i].w;
if(ans > dis[0][u] + dis[1][v] + dist / 2)
ans = dis[0][u] + dis[1][v] + dist / 2;
}
printf("%I64d\n", ans);
}
return 0;
}