1. 程式人生 > >poj3613:Cow Relays(倍增優化+矩陣乘法floyd+快速冪)

poj3613:Cow Relays(倍增優化+矩陣乘法floyd+快速冪)

phy rails 模板 矩陣 structure ssi 進制 size and

Cow Relays

Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 7825 Accepted: 3068

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 ≤ I

1i ≤ 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: N, T, S, 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

題意

給出一張圖,求k邊最短路,即經過k條邊的最短路。

分析

思考一下:如果一個矩陣,表示走k條邊後,一張圖的點與點的最短路徑,(a,b)表示從a到b的最短路徑,然後我們把它與自己,按照矩陣乘法的格式“相乘”,把其中的乘改為取min,c.a[i][j] = min(c.a[i][j],x.a[i][k]+y.a[k][j]);看不懂先看下面。

這樣得到的是走k+k條邊的矩陣。有點抽象,下面詳細解釋下:

c中的一個點(a,b),當我們用a矩陣和b矩陣求它時,我們枚舉了x矩陣的a行所有數,與y矩陣的b列所有數,並且他們的坐標只能是相對應的,比如x矩陣的(a,2)這個點,相應的y矩陣點就是(2,b),那麽放到圖上去理解,即從a點經過2點到b點的距離,類似的點不只有2,把所有點枚舉完後,c.a[a][b]就是從a到b的最短距離。(意會一下)

這樣下來,會得到走k+k條邊的最短路徑,對於其他的矩陣這樣操作,得到的是他們兩個,經過的邊數相加的結果。(一個經過a條邊後的矩陣 與 一個經過b條邊後的矩陣這樣操作後,是經過a+b條邊後的矩陣,矩陣中存的是最短路徑)。解釋一下:向上面的例子一樣,(a,2)(2,b),是即從a點經過2點到b點的距離,因為x矩陣和y矩陣都是走k條邊後的最短路徑,那麽x矩陣中的(a,2)是走k步後的最短路徑,(2,b)也是,那麽他們相加不就是走k+k條邊後的最短路徑嗎?其他的矩陣一樣。

然後,就可以套用快速冪的模板了,只不過將以前的乘改成加了,也就是倍增的思想的,比如對於走10條邊,它的二進制是1010,那麽我們就讓在走2(10)邊時的矩陣 乘以 8(1000)邊的矩陣,得到走10條邊的矩陣即開始時由1->2->4->8->16……即倍增中的2次冪。

code

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<map>
 4 #include<cstring>
 5 
 6 using namespace std;
 7 const int MAXN = 210;
 8 
 9 int Hash[1010];
10 int n,k,q,z,tn; 
11 
12 int read()
13 {
14     int x = 0,f = 1;char ch = getchar();
15     while (ch<0||ch>9) {if (ch=-) f=-1;ch = getchar(); }
16     while (ch>=0&&ch<=9){x = x*10+ch-0;ch = getchar(); }
17     return x*f;
18 }
19 
20 struct Matrix{
21     int a[MAXN][MAXN];
22     Matrix operator * (const Matrix &x) const 
23     {
24         Matrix c;
25         memset(c.a,0x3f,sizeof(c.a));
26         for (int k=1; k<=tn; k++)
27             for (int i=1; i<=tn; ++i)
28                 for (int j=1; j<=tn; ++j)
29                     c.a[i][j] = min(c.a[i][j],a[i][k]+x.a[k][j]);
30         return c;
31      } 
32 }s,ans;
33 void ksm()
34 { 
35     ans = s;
36     k--;
37     for (; k; k>>=1)
38     {
39         if (k&1) ans = ans*s;
40         s = s*s;
41     }
42 }
43 int main()
44 {
45     k = read();n = read();q = read();z = read();
46     memset(s.a,0x3f,sizeof(s.a));
47     for (int x,y,w,i=1; i<=n; ++i)
48     {
49         w = read();x = read();y = read();
50         if (!Hash[x]) Hash[x] = ++tn;
51         if (!Hash[y]) Hash[y] = ++tn;
52         s.a[Hash[x]][Hash[y]] = s.a[Hash[y]][Hash[x]] = w;
53     }
54     ksm();
55     printf("%d",ans.a[Hash[q]][Hash[z]]);
56     return 0;
57 }

poj3613:Cow Relays(倍增優化+矩陣乘法floyd+快速冪)