DUT 胡老师的跨国逃亡

点击浏览题目大意:

/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, - 1sizeof(first));
    memset(vis,  0sizeof(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( 11);
    spfa( 22);
     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;
}

 

你可能感兴趣的:(du)