您的位置:首页 > 其它

POJ 3735 矩阵乘法的小优化GET。

2014-04-25 22:08 260 查看
Training little cats

Time Limit: 2000MSMemory Limit: 65536K
Total Submissions: 9408Accepted: 2253
Description

Facer's pet cat just gave birth to a brood of little cats. Having considered the health of those lovely cats, Facer decides to make the cats to do some exercises. Facer has well designed a set of moves for his cats. He is now asking you to supervise the
cats to do his exercises. Facer's great exercise for cats contains three different moves:

g i : Let the ith cat take a peanut.

e i : Let the ith cat eat all peanuts it have.

s i j : Let the ith cat and jth cat exchange their peanuts.

All the cats perform a sequence of these moves and must repeat it m times! Poor cats! Only Facer can come up with such embarrassing idea.

You have to determine the final number of peanuts each cat have, and directly give them the exact quantity in order to save them.

Input

The input file consists of multiple test cases, ending with three zeroes "0 0 0". For each test case, three integers
n, m and k are given firstly, where n is the number of cats and
k is the length of the move sequence. The following k lines describe the sequence.

(m≤1,000,000,000, n≤100, k≤100)

Output

For each test case, output n numbers in a single line, representing the numbers of peanuts the cats have.

Sample Input
3 1 6
g 1
g 2
g 2
s 1 2
g 3
e 2
0 0 0

Sample Output
2 0 1
题目大意是:有n只开始木有花生吃的小猫,然后给你k个操作,而操作的情况有三种:g i表示第i只小猫得到一个花生 e i表示第i只小猫把花生全吃了, s i j表示第i只小猫
            和第j只小猫交换花生个数,然后这k个操作执行m次,问最后各个小猫的花生个数。
思路分析:额,很显然是矩阵快速幂了,构造矩阵是关键。。 这题老头子在我大一暑假就给我讲过,但是当时连快速幂是啥都不知道就不了了之了,后来又看到这道题就把它写
          了,首先我们单独来看。
对于第一种情况,得到一个花生的状态,额这个也算是本题唯一巧妙的地方吧,就是原本是n*n阶的矩阵增广为n+1*n+1阶的矩阵,为什么呢,因为我们不妨来看样例三只猫的情况
如何对猫进行+1个花生的操作,我们可以想象有一只虚拟的猫有1个花生来提供,那么如果对于第一只猫获得一个花生我们可以构造如下矩阵:
|1 0 0 0 | | 1 |      | 1 |
|1 1 0 0 |*| 0 |----->| 1 |  因此一般而言对于第i只猫获得一个花生只要在对应的n+1阶矩阵中的第i行第0列将0变成1即可。
|0 0 1 0 | | 0 |      | 0 |
|0 0 0 1 | | 0 |      | 0 |
接下来是e操作,也就是表示第i只猫把花生全吃光,那么此时只要将初等矩阵中的第i行全部清零即可
例如:
|1 0 0 0 |  | 1 |       | 1 |
|0 0 0 0 |  | 1 |       | 0 |
|0 0 0 0 |* | 0 |------>| 0 |      表示第一只猫的花生吃光了
|0 0 0 0 |  | 0 |       | 0 |
最后是s操作,要求交换,实际上也就是交换第i和第j只猫咪的花生数,实际上也就是要把初等矩阵的第i j两行整体交换即可- -额好麻烦不举例子了
接着就是进行k次操作,构造出base矩阵,然后去快速幂。。。
一切貌似都按照计划很好的进行了,而且样例也过了。。 BUT 却T了八次。。。。
为什么。。。 后面才发现是卡了矩阵乘法复杂度。。。
一般而言矩阵乘法的朴素算法为O(n^3),但是我们发现在这个n+1阶矩阵中非零元素的个数至多为k个,所以是一个稀疏矩阵,因此可以对矩阵进行优化,当a[i][j]=0时就没必要
进入循环再去乘了。。。这样可以将矩阵乘法予以一定的优化。。。 然后。。就过了。。。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
long long n,m,k;

struct juzhen{

long long m[105][105];

};

juzhen mut(juzhen a,juzhen b)
 {
      juzhen c;
      memset(c.m,0,sizeof(c.m));
      for(int i=0;i<=n;i++)
      {
         for(int j=0;j<=n;j++)
          {
             if(a.m[i][j])

                 for(int k=0;k<=n;k++)
                      c.m[i][k]+=a.m[i][j]*b.m[j][k];

         }
      }
      return c;
  }//稀疏矩阵的矩阵乘法
juzhen pow(juzhen a,long long p)
{
    juzhen ans;
    memset(ans.m,0,sizeof(ans.m));
    for(int i=0;i<=n;i++)
    {
        ans.m[i][i]=1;
    }

    while(p)
    {
        if(p%2==0)
        {
            a=mut(a,a);
            p/=2;
        }
        else
        {
            ans=mut(ans,a);

            p--;
        }
    }
    return ans;
}

int main()
{
    while(scanf("%I64d%I64d%I64d",&n,&m,&k)!=EOF)
    {
        if(n==0&&m==0&&k==0)
        {
            return 0;
        }
       juzhen ans;
       memset(ans.m,0,sizeof(ans.m));
       for(int i=0;i<=n;i++)
       {
           ans.m[i][i]=1;
       }

        while(k--)
        {
            long long x,y;
            char s[15];
            scanf("%s",s);
            if(s[0]=='g')
            {
               scanf("%I64d",&x);
                ans.m[x][0]++;
            }
            else if(s[0]=='e')
            {
               scanf("%I64d",&x);
                for(int i=0;i<=n;i++)
                {
                    ans.m[x][i]=0;
                }
            }
            else if(s[0]=='s')
            {
                scanf("%I64d%I64d",&x,&y);
                for(int i=0;i<=n;i++)
                {
                    swap(ans.m[x][i],ans.m[y][i]);
                }
            }
        }
        if(m==0)
        {
            printf("0");
            for(int i=2;i<=n;i++)
            {
                printf(" 0");
            }
            printf("\n");
            continue;
        }
        ans=pow(ans,m);
        printf("%I64d",ans.m[1][0]);
        for(int i=2;i<=n;i++)
        {
            printf(" %I64d",ans.m[i][0]);
        }
        printf("\n");
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: