POJ 3735 Training little cats 矩陣二分冪 + 矩陣優化

來源:http://poj.org/problem?id=3735

題意:有一些貓,這些貓可以獲得一些花生,有三種操作:某隻貓可以獲得一個花生;某隻貓花生變爲0;兩隻貓的花生數目交換。問經過k次交換,且k次交換循環m次之後,每隻貓有多少花生。

思路:因爲貓的數量不多(<= 100),所以,可以用矩陣做,每種操作對應一個矩陣,矩陣相乘即可。循環m次即是矩陣的m次方,可以用矩陣二分冪。還有就是矩陣 乘法的優化,只有這樣纔可過。

矩陣乘法優化:

	  for(int i = 0; i <= n; ++i){
		for(int j = 0; j <= n; ++j){
			if(initm[i][j] == 0) continue;
			for(int k = 0; k <= n; ++k){
			  mm[i][k] += initm[i][j] * dd[j][k];
			}
		}
	  }

全部代碼:

#include <iostream>
#include <cstdio>
#include <string.h>
using namespace std;

typedef long long LL;
const int N = 110;
int n,m,k;
LL initm[N][N],addm[N][N],zerom[N][N],exchm[N][N],dd[N][N];
void init(){
	memset(initm,0,sizeof(initm));
	for(int i = 0; i <= n; ++i){
	   initm[i][i] = 1;
	}
}
void add(int x){
	memset(addm,0,sizeof(addm));
	for(int i = 0; i <= n; ++i)
		addm[i][i] = 1;
	addm[n][x-1] = 1;
}
void zero(int x){
	memset(zerom,0,sizeof(zerom));
	for(int i = 0; i <= n; ++i)
		zerom[i][i] = 1;
	zerom[x-1][x-1] = 0;
}
void exch(int x,int y){
	memset(exchm,0,sizeof(exchm));
	for(int i = 0; i <= n; ++i)
		exchm[i][i] = 1;
	exchm[x-1][x-1] = 0;
	exchm[y-1][y-1] = 0;
	exchm[y-1][x-1] = 1;
	exchm[x-1][y-1] = 1;
}
void mult(LL mm[N][N],LL temp[N][N]){
	LL newmm[N][N];
	memset(newmm,0,sizeof(newmm));
	for(int i = 0; i <= n; ++i){
		for(int j = 0; j <= n; ++j){
			if(mm[i][j] == 0) continue;
			for(int k = 0; k <= n; ++k){
			  newmm[i][k] += mm[i][j] * temp[j][k];
			}
		}
	}
	memset(mm,0,sizeof(mm));
	for(int i = 0; i <= n; ++i){
	   for(int j = 0; j <= n; ++j)
		   mm[i][j] = newmm[i][j];
	}
}
void mult2(int x){
	LL newmm[N][N];
	memset(newmm,0,sizeof(newmm));
	for(int i = 0; i <= n; ++i){
		for(int j = 0; j <= n; ++j){
			if(initm[i][j] == 0)
				continue;
			for(int k = 0; k <= n; ++k){
			  newmm[i][k] += initm[i][j] * initm[j][k];
			}
		}
	}
	for(int i = 0; i <= n; ++i){
	   for(int j = 0; j <= n; ++j)
		   initm[i][j] = newmm[i][j];
	}
	if(x){
	  LL mm[N][N];
	  memset(mm,0,sizeof(mm));
	  for(int i = 0; i <= n; ++i){
		for(int j = 0; j <= n; ++j){
			if(initm[i][j] == 0) continue;
			for(int k = 0; k <= n; ++k){
			  mm[i][k] += initm[i][j] * dd[j][k];
			}
		}
	  }
	  for(int i = 0; i <= n; ++i){
		  for(int j = 0; j <= n; ++j){
		    initm[i][j] = mm[i][j];
		  }
	  }
	}
}
void binary_power(int x){
	if(x == 1)
		return;
	binary_power(x/2);
	if(x % 2)
		mult2(1);
	else
		mult2(0);
}
int main(){
	//freopen("1.txt","r",stdin);
	while(scanf("%d%d%d",&n,&m,&k)){
	   if(n + m + k == 0)
		   break;
	   init();
	   char ch;
	   int x,y;
	   while(k--){
	     cin >> ch;
		 if(ch == 'g'){
		   scanf("%d",&x);
		   add(x);
		   mult(initm,addm);
		 }
		 else if(ch == 'e'){
		   scanf("%d",&x);
		   zero(x);
		   mult(initm,zerom);
		 }
		 else{
		   scanf("%d%d",&x,&y);
		   exch(x,y);
		   mult(initm,exchm);
		 }
	   }
	   for(int i = 0; i <= n; ++i){
	      for(int j = 0; j <= n; ++j)
			  dd[i][j] = initm[i][j];
	   }
	   if(m == 0){
	     for(int i = 0; i < n - 1; ++i)
			 printf("0 ");
		 printf("0\n");
		 continue;
	   }
	   binary_power(m);
	   for(int i = 0; i < n - 1; ++i){
	     printf("%lld ",initm[n][i]);
	   }
	   printf("%lld\n",initm[n][n-1]);
	}
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章