点击浏览题目大意:
/Files/g0feng/胡老师的跨国逃亡.doc
关于这道题,是我在学习图论时一本参考书上看到的题目,觉得有趣,就写了写。
大概思路:第一次我思考时,首先是找到A国中的边界点,然后找出1到边界点距离的最小值,然后通过通过spfa枚举边界点的去找离2的最小值,但这样应该会超时。于是我将地图预处理了一下,首先找到1离A中所有的点的最短路,然后去找2离B中所有的点的最短路。这里需要注意一下的就是怎么样去保证d[i]一定是代表一个国家之内的最小值,这里我们可以加一个判断,即vis[v] == f。记得把初始值d[src]置为0,这样,我们最后求得的距离一定是国家与国家之间的最小值。
然后怎么去找边界点呢?我们可以另外开一个数组来存储边,这样只要vis[u] != vis[v]的话,说明它就是边界点,由于d[i]一定代表国家与国家之间的最小值,然后通过枚举判断最小值即可。
CODE:
#include <iostream>
#include <cstring>
#include <
string>
#include <cstdio>
#include <cstdlib>
#include <map>
#include <queue>
using
namespace std;
const
int MAXN =
3010;
const
int MAXM =
500510;
const
int INF =
0x3f3f3f3f;
struct Edge
{
int u, v, w;
int next;
}edge[MAXN], Save[MAXN];
//
Save储存边的值
int n, m;
int cnt;
int first[MAXN], d[MAXN];
int vis[MAXN];
void init()
{
cnt =
0;
memset(first, -
1,
sizeof(first));
memset(vis,
0,
sizeof(vis));
memset(d, INF,
sizeof(d));
}
void read_graph(
int u,
int v,
int w)
{
edge[cnt].v = v, edge[cnt].w = w;
edge[cnt].next = first[u], first[u] = cnt++;
}
void read_case()
{
init();
for(
int i =
1; i <= m; i++)
{
int u, v, w;
scanf(
"
%d%d%d
", &u, &v, &w);
read_graph(u, v, w);
read_graph(v, u, w);
Save[i].u = u, Save[i].v = v, Save[i].w = w;
}
int f;
for(
int i =
1; i <= n; i++)
{
scanf(
"
%d
", &f);
vis[i] = f;
}
}
void spfa(
int src,
int f)
{
queue<
int> q;
bool inq[MAXN] = {
0};
d[src] =
0;
//
初始点需要置0
q.push(src);
while(!q.empty())
{
int x = q.front(); q.pop();
inq[x] =
0;
for(
int e = first[x]; e != -
1; e = edge[e].next)
{
int v = edge[e].v, w = edge[e].w;
if(d[v] > d[x] + w && vis[v] == f)
//
枚举每个A或者B国家中到源点的最短距离
{
d[v] = d[x] + w;
if(!inq[v])
{
inq[v] =
1;
q.push(v);
}
}
}
}
}
void solve()
{
int ans = INF;
read_case();
spfa(
1,
1);
spfa(
2,
2);
for(
int i =
1; i <= m; i++)
{
int u = Save[i].u, v = Save[i].v, w = Save[i].w;
//
储存边,枚举时需要用到
if(vis[u] != vis[v])
{
if(d[u] + d[v] + w < ans)
{
ans = d[u] + d[v] + w;
}
}
}
if(ans < INF)
{
printf(
"
%d\n
", ans);
}
else printf(
"
-1\n
");
}
int main()
{
while(~scanf(
"
%d%d
", &n, &m))
{
solve();
}
return
0;
}