1. 程式人生 > >poj3735—Training little cats(特殊操作轉化為矩陣操作)

poj3735—Training little cats(特殊操作轉化為矩陣操作)

logs cout att 接下來 tor 成了 pre 組成 little

題目鏈接:http://poj.org/problem?id=3735

題目意思:

調教貓咪:有n只饑渴的貓咪,現有一組羞恥連續操作,由k個操作組成,全部選自:

1. g i 給第i只貓咪一顆花生

2. e i 讓第i只貓咪吃光它的花生

3. s i j 交換貓咪i與貓咪j的花生

現將上述一組連續操作做m次後,求每只貓咪有多少顆花生?

思路:這道題難點在如何把這種奇怪的操作轉化為矩陣操作,網絡上看到一個畫的很好的圖,這裏直接偷過來。

技術分享

現在,對於每一個操作我們都可以得到一個轉置矩陣,把k個操作的矩陣相乘我們可以得到一個新的轉置矩陣T。A * T 表示我們經過一組操作,類似我們可以得到經過m組操作的矩陣為 A * T ^ m,最終矩陣的[0][1~n]即為答案。

上述的做法比較直觀,但是實現過於麻煩,因為要構造k個不同矩陣。有沒有別的方法可以直接構造轉置矩陣T?答案是肯定的。

我們還是以單位矩陣為基礎:

對於第一種操作g i,我們使Mat[0][i] = Mat[0][i] + 1
對於第二種操作e i,我們使矩陣的第i列清零;
對於第三種操作s i j,我們使第i列與第j列互換。
這樣實現的話,我們始終在處理一個矩陣,免去構造k個矩陣的麻煩。
至此,構造轉置矩陣T就完成了,接下來只需用矩陣快速冪求出 A * T ^ m即可,還有一個註意的地方,該題需要用到long long。

這裏還要說一下T*A=A*T的轉置。

代碼:

技術分享
 1 //Author: xiaowuga
2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #define maxx INT_MAX 6 #define minn INT_MIN 7 #define inf 0x3f3f3f3f 8 #define N 105 9 using namespace std; 10 typedef long long ll; 11 ll n,size;//第n項,矩陣大小 12 struct Matrix{ 13 ll mat[N][N]; 14 void clear(){
15 memset(mat,0,sizeof(mat)); 16 } 17 Matrix operator * (const Matrix & m) const{ 18 Matrix tmp; 19 int i ,j,k; 20 tmp.clear(); 21 for( i=0;i<size;i++) 22 for( k=0;k<size;k++){ 23 if(mat[i][k]==0) continue; 24 for( j=0;j<size;j++){ 25 tmp.mat[i][j]+=mat[i][k]*m.mat[k][j]; 26 } 27 } 28 return tmp; 29 } 30 }; 31 void POW(Matrix m,ll k){ 32 Matrix ans; 33 memset(ans.mat,0,sizeof(ans.mat)); 34 for(int i=0;i<size;i++) ans.mat[i][i]=1; 35 while(k){ 36 if(k&1) ans=ans*m; 37 k/=2; 38 m=m*m; 39 } 40 for(int i=1;i<size;i++){ 41 cout<<ans.mat[0][i]<<" "; 42 } 43 cout<<endl; 44 } 45 int main() { 46 Matrix m; 47 int k; 48 while(cin>>size>>n>>k&&(size+n+k)){ 49 size++; 50 m.clear(); 51 for(int i=0;i<size;i++) m.mat[i][i]=1; 52 for(int i=0;i<k;i++){ 53 char t[5]; 54 int num1,num2; 55 cin>>t; 56 if(t[0]==g){ 57 cin>>num1; 58 m.mat[0][num1]++; 59 } 60 else if(t[0]==e){ 61 cin>>num1; 62 for(int j=0;j<size;j++){ 63 m.mat[j][num1]=0; 64 } 65 } 66 else{ 67 cin>>num1>>num2; 68 for(int j=0;j<size;j++) 69 swap(m.mat[j][num1],m.mat[j][num2]); 70 } 71 } 72 POW(m,n); 73 } 74 return 0; 75 }
View Code

poj3735—Training little cats(特殊操作轉化為矩陣操作)