poj 3735 Training little cats

本文讨论了一个使用矩阵快速幂解决猫食分配问题的算法。通过构造特定的矩阵和操作,实现了对大量操作的高效模拟。文章详细介绍了矩阵构造方法及其实现过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

  矩阵快速幂的题。表示yy了很长一段时间才想到怎么构造矩阵。。。。不过过了sample以后就1y了!

  简单的说一下构造的方法:一个原始矩阵(代码里面的Base)只用到第一行。前面n个表示的是每只猫拥有的食物,因为刚开始的时候所有猫都是没有食物的,所以全部设置为0。紧接着的n个数表示的是每一个循环里食物数量的改变值。然后就是每个循环的操作,也就是代码里的op矩阵。这个矩阵是这样设置的,初始化的时候,分成四块,其中有三块矩阵是单位矩阵。然后,对于每一个题目要求的操作,食物加一就是Base矩阵后半部分相应位置加一,食物交换就是op矩阵相应的两列交换过来,清空食物就是将op的相应的位置(对应这里的猫拥有的食物的位置)以及将Base中循环里的食物的数量改变值清空。

  可以这样想,现在我们需要的是利用矩阵来简化100个操作的循环,那么要怎样设置矩阵才能实现这样的功能呢?其实将每次循环后每只猫拥有的食物的数量和循环前做对比,可以发现操作后的每个位置的值只是由两部分组成。一部分是上一循环结束后,某一只猫拥有的食物的量,另一部分是循环过后对于这个位置的猫的食物的变化量。于是,处理好操作矩阵,每次就可以用同样的矩阵来模拟循环的操作了。

代码如下:

View Code
  1 #include <cstdio>
  2 #include <cstring>
  3 #include <cstdlib>
  4 #include <algorithm>
  5 
  6 using namespace std;
  7 typedef __int64 ll;
  8 const int matSize = 200;
  9 int calSize = matSize;
 10 
 11 struct Matrix {
 12     ll val[matSize][matSize];
 13 
 14     Matrix(bool Init = false) {
 15         for (int i = 0; i < calSize; i++) {
 16             for (int j = 0; j < calSize; j++) {
 17                 val[i][j] = 0;
 18             }
 19             if (Init) val[i][i] = 1;
 20         }
 21     }
 22 
 23     void print() {
 24         for (int i = 0; i < calSize; i++) {
 25             for (int j = 0; j < calSize; j++) {
 26                 printf("%I64d ", val[i][j]);
 27             }
 28             puts("");
 29         }
 30         puts("~~~");
 31     }
 32 } Base, op;
 33 
 34 Matrix operator * (Matrix &_a, Matrix &_b) {
 35     Matrix ret = Matrix();
 36 
 37     for (int i = 0; i < calSize; i++) {
 38         for (int k = 0; k < calSize; k++) {
 39             if (_a.val[i][k]) {
 40                 for (int j = 0; j < calSize; j++) {
 41                     ret.val[i][j] += _a.val[i][k] * _b.val[k][j];
 42                 }
 43             }
 44         }
 45     }
 46 
 47     return ret;
 48 }
 49 
 50 Matrix operator ^ (Matrix &_a, ll _p) {
 51     Matrix ret = Matrix(true);
 52 
 53     while (_p) {
 54         if (_p & 1) {
 55             ret = ret * _a;
 56         }
 57         _a = _a * _a;
 58         _p >>= 1;
 59     }
 60 
 61     return ret;
 62 }
 63 
 64 Matrix operator + (Matrix &_a, Matrix &_b) {
 65     for (int i = 0; i < calSize; i++) {
 66         for (int j = 0; j < calSize; j++) {
 67             _a.val[i][j] = _a.val[i][j] + _b.val[i][j];
 68         }
 69     }
 70 
 71     return _a;
 72 }
 73 
 74 void deal(int n, ll m, int k) {
 75     char buf[3];
 76     int a, b;
 77     int pos[101];
 78 
 79     calSize = n << 1;
 80     op = Matrix();
 81     Base = Matrix();
 82     for (int i = 0; i < n; i++) {
 83         pos[i] = i;
 84         op.val[i][i] = op.val[i + n][i] = op.val[i + n][i + n] = 1;
 85     }
 86     while (k--) {
 87         scanf("%s", buf);
 88         switch (buf[0]) {
 89         case 'g':
 90             scanf("%d", &a);
 91             Base.val[0][pos[a - 1] + n]++;
 92             break;
 93         case 'e':
 94             scanf("%d", &a);
 95             Base.val[0][pos[a - 1] + n] = 0;
 96             op.val[pos[a - 1]][a - 1] = 0;
 97             break;
 98         case 's':
 99             scanf("%d%d", &a, &b);
100             swap(pos[a - 1], pos[b - 1]);
101             for (int i = 0, endi = n << 1; i < endi; i++) {
102                 swap(op.val[i][a - 1], op.val[i][b - 1]);
103             }
104             break;
105         }
106     }
107 //    puts("Base");
108 //    Base.print();
109     op = op ^ m;
110 //    puts("op");
111 //    op.print();
112 
113     Matrix ans = Base * op;
114 //    ans.print();
115 
116     for (int i = 0; i < n; i++) {
117         if (i) putchar(' ');
118         printf("%I64d", ans.val[0][i]);
119     }
120     puts("");
121 }
122 
123 int main() {
124     int n, k;
125     ll m;
126 
127     freopen("in", "r", stdin);
128     while (~scanf("%d%I64d%d", &n, &m, &k)&& (n || m || k)) {
129         deal(n, m, k);
130     }
131 
132     return 0;
133 }

 

——written by Lyon

转载于:https://www.cnblogs.com/LyonLys/archive/2012/09/29/poj_3735_Lyon.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值