題解第二部分
**** 原題來自:scoi 2009**
windy 在有向圖中迷路了. 該有向圖有 n
nn個節點,windy 從節點 0
00 出發,他必須恰好在t
tt時刻到達節點 n−1
n-1n−
1。現在給出該有向圖,你能告訴 windy 總共有多少種不同的路徑嗎?
注意:windy 不能在某個節點逗留,且通過某有向邊的時間嚴格為給定的時間。
第一行包含兩個整數n
nn,ttt;
接下來有 n
nn行,每行乙個長度為n
nn的字串。第i
ii行第j
jj列為 0表示從節點i
ii到節點j
jj沒有邊,為1
11到9
99表示從節點i
ii節點j
jj需要耗費的時間。
包含乙個整數,可能的路徑數,這個數可能很大,只需輸出這個數除以2009
2009
2009
的餘數。
2 2
1100
1
5 30
12045
07105
47805
12024
12345
852
2 <= n <= 10 ; 1 <= t <= 1000000000 ;0<=邊權<=9;
第一反應:咦?這不是圖論嗎???
默默的看了眼t的範圍,死了心
dp!! dp一定可以!!!
默默的看了眼t的範圍,又死了心
那麼怎麼做呢?
首先,我們把這道題想簡單一點,如果題目中的每一條邊都沒有邊權,只用1或0來表示兩個點之間是否存在邊,並且用鄰接矩陣來存這張圖,那麼我們又可以得到些什麼呢?
我們以下面這張圖為例
以鄰接矩陣來表示這個矩陣:
0 1 1
1 0 1
1 0 0 //矩陣1
其中,ai
j表示i到j之間是否有連線;
2 0 1
1 1 1
0 1 1 //矩陣2
你又發現了什麼呢?
好的,如果還沒發現,我們再來將矩陣1三次方一下:
1 2 2
2 1 2
2 0 1 //矩陣3
什麼,你還沒發現嗎???
那麼讓我來告訴你吧!!!
仔細觀察矩陣1,我們可以把aij看成通過一條邊,由i到達j的情況總數
矩陣2、矩陣3也是如此;
不信?我們舉個栗子:
從點1到點2,且通過一條邊的情況不存在,記為0;
從點1到點2,且通過兩條邊的情況共兩種(1->2->1 and 1->3->1),記為2;
從點1到點2,且通過三條邊的情況僅有一種(1->2->3->1),記為1;
再回頭看看矩陣吧!!!是不是完全滿足這個條件呢???
所以我們就可以得出結論啦:
在矩陣ax中,ax
ij表示由i到j經過x條邊的情況總數
所以這就可以運用快速冪啦!!!
仔細算一下時間複雜度,o(n*logn),穩穩滴!!!
那麼,這道題就可以很快打出來啦——嗎?
顯然是不可以的。
可能你已經發現了,我們所有的推論都建立在邊權為1的情況上,可是這道題目呢?
接下來有 n呀呀呀,這道題目的邊權不只是1呀!nn行,每行乙個長度為n
nn的字串。第i
ii行第j
jj列為 0表示從節點i
ii到節點j
jj沒有邊,為1
11到9
99表示從節點i
ii到節點j
jj需要耗費的時間。
!(⊙ o ⊙)!
怎麼辦呢?
雖然我們發現不能直接使用我們的結論,但是最大邊權是9!n也不超過10!都不算大!
那我們就可以採用一種叫做拆點的方法:把乙個點拆成10個點。
並且,我們發現即使如此拆點,n也不會超過100,妥妥的可以呀!
但怎麼拆點呢?
我們先來試一下拆乙個邊權不超過2的圖吧!
可得矩陣
0 2
2 1
將其拆點:
把1.1看成節點1;
把1.2看成節點2;
把2.1看成節點3;
把2.2看成節點4;
可得到新矩陣 :
0 1 0 0
0 0 1 0
0 0 1 1
1 0 0 0
將其平方:
0 0 1 0
0 0 1 1
1 0 1 1
0 1 0 0
再驗算一下,
原來有點1到點2並用經過2邊權的方案總數有一種(1->2,邊權為2);
現在來說,點1變為點1,點2變為點3,經過2邊權的方案總數依舊是2(1->2->3,邊權均為1);
那麼則說明我們的拆點是正確的。
那麼怎麼做呢?
我們再對非零點進行分類,原先就有的1看成藍色,後面通過自連得到的1看成紅色:
那麼下面的**就可以進行拆點操作:
int
cheak
(int i,
int j)
void
chaidian()
for(
int j=
1;j<=n;j++)}
}}
那麼既然我們通過拆點操作將所有點之間的邊權都變成了1,那麼我們就可以用剛才得到的定理啦!!!
#include
using
namespace std;
int n,t;
const
long
long mod=
2009
;struct matrix
}a;matrix yunsuan
(matrix x, matrix y)}}
return now;
}matrix power
(matrix a,
int b)
while
(b)return now;
}int
cheak
(int i,
int j)
intmain()
for(
int j=
1;j<=n;j++)}
} a=
power
(a,t)
;printf
("%d\n"
,a.ma[1]
[10*n-9])
;}
To Heart 題解 戳西瓜
請不要吝嗇你的點讚!有 n 個西瓜,編號為0 到 n 1,每個西瓜上都標有乙個數字,這些數字存在陣列 nums 中。現在要求你戳破所有的西瓜。每當你戳破乙個西瓜 i 時,你可以獲得 nums left nums i nums right 個硬幣。這裡的 left 和 right 代表和 i 相鄰的兩...
To Heart 題解 內需消費
題目鏈結 首先,我們先假設這道題不需要修改物價,那麼我們如何找到最好的情況呢?差分。如下數列 1 4 3 5 2很容易觀察出,在第乙個商店到第二個商店中,我們最多可以賺3元,在第乙個商店進貨,第二個商店賣出。但是在第二個商店到第三個商店的途中,我們不能賺錢。因為第二個商店的 比第三個商店的 的 大,...
To Heart 題解 內需消費
題目鏈結 首先,我們先假設這道題不需要修改物價,那麼我們如何找到最好的情況呢?差分。如下數列 1 4 3 5 2很容易觀察出,在第乙個商店到第二個商店中,我們最多可以賺3元,在第乙個商店進貨,第二個商店賣出。但是在第二個商店到第三個商店的途中,我們不能賺錢。因為第二個商店的 比第三個商店的 的 大,...