ACM: 经过K条边的最短路 图论题 po…

来源:互联网 发布:提花组织软件 编辑:程序博客网 时间:2024/06/03 19:59
Cow Relays
Description

For their physical fitness program, N (2 ≤ N ≤1,000,000) cows have decided to run a relay race using the T(2 ≤ T ≤ 100) cow trails throughout the pasture.

Each trail connects two different intersections (1 ≤I1i ≤ 1,000; 1 ≤I2i ≤ 1,000), each of which is thetermination for at least two trails. The cows know thelengthi of each trail (1 ≤lengthi  ≤ 1,000), the twointersections the trail connects, and they know that no twointersections are directly connected by two different trails. Thetrails form a structure known mathematically as a graph.

To run the relay, the N cows position themselves atvarious intersections (some intersections might have more than onecow). They must position themselves properly so that they can handoff the baton cow-by-cow and end up at the proper finishingplace.

Write a program to help position the cows. Find the shortestpath that connects the starting intersection (S) and theending intersection (E) and traverses exactly N cowtrails.

Input

* Line 1: Four space-separated integers: N, T,S, and E
* Lines 2..T+1: Line i+1 describes trail iwith three space-separated integers: lengthi ,I1i , and I2i

Output

* Line 1: A single integer that is the shortest distance fromintersection S to intersection E that traversesexactly N cow trails.

Sample Input

2 6 6 4
11 4 6
4 4 8
8 4 9
6 6 8
2 6 9
3 8 9

Sample Output

10

题意: 牛牛接力赛, 有一个无向图, 要你求出从start到end点的经过k条边的最短路.

解题思路: (WA了好多次, 是点映射的数组没有置零 T.T)
      1. 我不知道是自己读错题意还是网上的人理解错了, 两个交叉路口不能有两个不同的trails
         链接. 两个点之间是没有重边的.
      2. 从i到j经过k条边的路是否有, 可以通过01临接矩阵幂次得出.
      3. 但是题目是要求从i到j经过k条边的最短路.
      问题分析:
         我们不妨设dp[i][j][n]:表示从i到j经过n条边的最短路.
         即:dp[i][j][n] = min(dp[i][k][t]+dp[k][j][n-t]);
         讨论到这里, 我们妨思考怎么求出最短路问题. 显然floyd的DP思想.
         在这里可以发现如果我们把dp[i][j][n] = min(dp[i][k][n/2]+dp[k][j][n/2]);
         利用二分的思想+floyd问题就可以求解了.
      4. 其实说白了就是, 第一次i->k 一条边, k->j 一条边 2
                       第二次i->k 两条边, k->j 两条边 4
                              ......
                       第n次i->k 2^(n-1)条边, k->j 2^(n-1)条边 2^n
         (奇数的情况可以用来单独求一次floyd直接路).

代码:
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
#define MAX 210
const int INF = (1<<30)-1;

int n, T, start, end;
int num, node[1005];
int g[MAX][MAX], result[MAX][MAX], temp[MAX][MAX];

void floyd(int c[][MAX], int a[][MAX], int b[][MAX])
{
    for(int i = 1; i <= num; ++i)
        for(int j = 1; j <= num; ++j)
            c[i][j] = INF;
    for(int k = 1; k <= num; ++k)
        for(int i = 1; i <= num; ++i)
            for(int j = 1; j <= num; ++j)
                if(c[i][j] > a[i][k]+b[k][j])
                    c[i][j] = a[i][k]+b[k][j];
    for(int i = 1; i <= num; ++i)
        for(int j = 1; j <= num; ++j)
            a[i][j] = c[i][j];
}

void solve(int n)
{
    while(n)
    {
        if(n % 2 == 1)
            floyd(temp,result,g);
        floyd(temp,g,g);
        n /= 2;
     
}

int main()
{
//    freopen("input.txt","r",stdin);
    while(scanf("%d %d %d %d",&n, &T, &start, &end) != EOF)
    {
        for(int i = 0; i < MAX; ++i)
        {
            for(int j = 0; j < MAX; ++j)
                g[i][j] = result[i][j] = INF;
            result[i][i] = 0;
        }
       
        num = 0;
        int u, v, w;
        memset(node,0,sizeof(node));
        for(int i = 1; i <= T; ++i)
        {
            scanf("%d %d %d",&w,&u,&v);
            if(node[u] == 0)
                node[u] = ++num;
            if(node[v] == 0)
                node[v] = ++num;
            g[ node[u] ][ node[v] ] = g[ node[v] ][ node[u] ] = w;
        }
       
        solve(n);
        printf("%d\n",result[ node[start] ][ node[end] ]);
    }
    return 0;
}

0 0
原创粉丝点击