Poj 3613 Cow Relays【Floyd+快速幂】

Cow Relays

Time Limit: 1000MS

 

Memory Limit: 65536K

Total Submissions: 6793

 

Accepted: 2660

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 the termination for at least two trails. The cows know the lengthi of each trail (1 ≤ lengthi  ≤ 1,000), the two intersections the trail connects, and they know that no two intersections are directly connected by two different trails. The trails form a structure known mathematically as a graph.

To run the relay, the N cows position themselves at various intersections (some intersections might have more than one cow). They must position themselves properly so that they can hand off the baton cow-by-cow and end up at the proper finishing place.

Write a program to help position the cows. Find the shortest path that connects the starting intersection (S) and the ending intersection (E) and traverses exactly N cow trails.

Input

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

Output

* Line 1: A single integer that is the shortest distance from intersection S to intersection E that traverses exactly 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

Source

USACO 2007 November Gold

 

1、首先我们要理解这样一个问题,如果a【i】【j】表示图的初始邻接矩阵,b【i】【j】==a【i】【j】;

如果c【j】【k】=min(c【j】【k】,a【j】【i】+b【i】【k】){应用Floyd求最短路},其实不难理解,c【】【】得到的邻接矩阵是从b中拿出一条边,从a中拿出一条边构成的,那么如果初始a和

b就是邻接矩阵,那么c【i】【j】现在表示的含义就是从i到j一共经过两条边的最短路。


2、那么推广,如果现在让a【i】【j】=c【i】【j】,那么现在a【i】【j】现在表示的含义就是从i到j一共经过两条边的最短路。此时b【i】【j】不变,还是图的邻接矩阵,如果这时候c【j】【k】=min(c【j】【k】,a【j】【i】+b【i】【k】){应用Floyd求最短路}.那么c【】【】得到的邻接矩阵也是从a中拿出一条边,从b中拿出一条边构成的,然而这时候a中的一条边,其实相当于两条边,那么:c【i】【j】现在表示的含义就是从i到j一共经过三条边的最短路。


3、依次类推,如果需要经过k条边的从i到j的最短路,那么就进行k-1次上述过程即可。因为k可能比较大,而且每一次进行Floyd也是一个不小的开销,所以这k-1次乘法我们用快速幂的方式优化,最终得到正解。


Ac代码:


#include<stdio.h>
#include<string.h>
#include<stdio.h>
#include<map>
#include<iostream>
#include<algorithm>
using namespace std;
int head[100000];
struct EdgeNode
{
    int to;
    int w;
    int next;
}e[1000000];
int dis3[1005][1005];
int dis[1005][1005];
int dis2[1005][1005];
int q,m,ss,ee,n,cont;
void Floyd(int dis[1005][1005],int dis2[1005][1005])
{
    memset(dis3,0x3f3f3f3f,sizeof(dis3));
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            for(int k=1;k<=n;k++)
            {
                dis3[j][k]=min(dis3[j][k],dis[j][i]+dis2[i][k]);
            }
        }
    }
}
void init()
{
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            dis[i][j]=dis3[i][j];
        }
    }
}
void init2()
{
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            dis2[i][j]=dis3[i][j];
        }
    }
}
void Slove(int k)
{
    while(k)
    {
        if(k%2==1)
        {
            Floyd(dis,dis2);
            init();
        }
        k/=2;
        Floyd(dis2,dis2);
        init2();
    }
}
int main()
{
    while(~scanf("%d%d%d%d",&q,&m,&ss,&ee))
    {
        n=1;
        map<int,int >mp;
        memset(dis,0x3f3f3f3f,sizeof(dis));
        memset(dis2,0x3f3f3f3f,sizeof(dis2));
        for(int i=0;i<m;i++)
        {
            int x,y,w;
            scanf("%d%d%d",&w,&x,&y);
            if(mp[x]==0)
            {
                mp[x]=n++;
            }
            if(mp[y]==0)
            {
                mp[y]=n++;
            }
            x=mp[x];y=mp[y];
            dis[x][y]=dis[y][x]=w;
            dis2[x][y]=dis2[y][x]=w;
        }
        Slove(q-1);
        printf("%d\n",dis[mp[ss]][mp[ee]]);
    }
}







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值