博文

[置顶] pku题目分类,以后可以照着来练(2009-07-30 13:02:00)

摘要:主流算法: Ø          1.搜索 //回溯 Ø          2.DP(动态规划)  Ø          3.贪心  Ø          4.图论 //Dijkstra、最小生成树、网络流 Ø          5.数论 //解模线性方程 Ø          6.计算几何 //凸壳、同等安置矩形的并的面积与周长 Ø          7.组合数学 //Polya定理 Ø          8.模拟  Ø          9.数据结构 //并查集、堆 Ø          10.博弈论  1、    排序 1423, 1694, 1723, 1727, 1763, 1788, 1828, 1838, 1840, 2201, 2376, 2377, 2380,1318, 1877, 1928, 1971, 1974, 1990, 2001, 2002, 2092, 2379, 1002(需要字符处理,排序用快排即可) 1007(稳定的排序) 2159(题意较难懂) 223......

阅读全文(3019) | 评论:0

(原创)用矩阵连乘解决公式推导(2009-08-02 13:40:00)

摘要:前些天做了比赛,学到了矩阵连乘,直到今天才真正弄懂了。 TJU3318  Chinese rings,这就是简单的矩阵连乘的应用。 当然,学习这个首先要知道二分求幂。 我构造的矩阵是这样的,矩阵A: 1  2  1 1  0  0 0  0  1 起始矩阵是,矩阵B: f(2) f(1) 1 目标矩阵是矩阵C: f(n+1) f(n) 1 这样矩阵A*B就可得到矩阵 f(3) f(2) 1 A*(A*B)又可得到 f(4) f(3) 1 . . . . . 我感觉很巧妙,也是今天才刚刚体会的。 这样的话 A*A*A....*A*B就可以得到C,然后就得到我们的答案f(n) 我们可以先把前面n-1个A求出来,这里用到二分求幂的方法。 关于二分求幂,我刚开始也不懂。后来去网上搜了下才知道。 话不多说,上代码。 #include <stdio.h>#include <string.h>#define M 200907 void mulmatrix(__int64 a[][3],__int64 b[][3]){    int i,j,k;    __int64 c[3][3];    memset(c,0,sizeof(c));    for(i = 0;i < 3;i++)        for(j = 0;j < 3;j++)            for(k = 0;k < 3;k++)                c[i][j] = ( c[i][j] + ( ( a[i][k] * b[k][j] ) % M) ) % M; &nbs......

阅读全文(2654) | 评论:0

转自matrix67  十个利用矩阵乘法解决的经典问题(2009-08-01 17:13:00)

摘要:十个利用矩阵乘法解决的经典题目 from Matrix67 2009-07-15 16:48 好像目前还没有这方面题目的总结。这几天连续看到四个问这类题目的人,今天在这里简单写一下。这里我们不介绍其它有关矩阵的知识,只介绍矩阵乘法和相关性质。     不要以为数学中的矩阵也是黑色屏幕上不断变化的绿色字符。在数学中,一个矩阵说穿了就是一个二维数组。一个n行m列的矩阵可以乘以一个m行p列的矩阵,得到的结果是一个n行p列的矩阵,其中的第i行第j列位置上的数等于前一个矩阵第i行上的m个数与后一个矩阵第j列上的m个数对应相乘后所有m个乘积的和。比如,下面的算式表示一个2行2列的矩阵乘以2行3列的矩阵,其结果是一个2行3列的矩阵。其中,结果的那个4等于2*2+0*1:          下面的算式则是一个1 x 3的矩阵乘以3 x 2的矩阵,得到一个1 x 2的矩阵:          矩阵乘法的两个重要性质:一,矩阵乘法不满足交换律;二,矩阵乘法满足结合律。为什么矩阵乘法不满足交换律呢?废话,交换过来后两个矩阵有可能根本不能相乘。为什么它又满足结合律呢?仔细想想你会发现这也是废话。假设你有三个矩阵A、B、C,那么(AB)C和A(BC)的结果的第i行第j列上的数都等于所有A(ik)*B(kl)*C(lj)的和(枚举所有的k和l)。经典题目1 给定n个点,m个操作,构造O(m+n)的算法输出m个操作后各点的位置。操作有平移、缩放、翻转和旋转     这里的操作是对所有点同时进行的。其中翻转是以坐标轴为对称轴进行翻转(两种情况),旋转则以原点为中心。如果对每个点分别进行模拟,那么m个操作总共耗时O(mn)。利用矩阵乘法可以在O(m)的时间里把所有操作合并为一个矩阵,然后每个点与该矩阵相乘即可直接得出最终该点的位置,总共耗时O(m+n)。假设初始时某个点的坐标为x和y,下面5个矩阵可以分别对其进行平移、旋转、翻转和旋转操作。预先把所有m个操作所对应的矩阵全部乘起来,再乘以(x,y,1),即可一步得出最终点的位置。 ......

阅读全文(2308) | 评论:0

01背包与完全背包的心得(2009-07-31 21:36:00)

摘要:用一维写的代码。 01背包:   for(j = 1;j <= n;j++)                      for(i = v;i <= 0;i++)                           f[i] = max(f[i],f[i-c[j]]+d[j]);   完全背包:   for(j = 1;j <= n;j++)                      for(i = 0;i <= v;i++)                           f[i] = max(f[i],f[i-c[v]]+d[i]);     两个背包只差在内循环的顺便。因为如果是正着数的话,f[j][i]的状态就会由f[j][i-c[j]]来推导得。 显然f[j][i-c[j]]是已经进入第j种物品的子结果,这是不符合01背包的,而应该是无限背包的。......

阅读全文(1761) | 评论:0

简单的并查集 hdu1272(2009-07-27 15:00:00)

摘要:今天去杭电做了两道题,主要是看了杭电并查集的讲义。 感觉他讲得非常棒,纯入门了。 也在今天又学了一个新的知识,并查集,感到很高兴。 HDU1272 题目意思是找到判断是不是连通无环的图。 判断成环的时候,只要判断输入边的两个点。有一个共同的父节点,那么这两个点就成环。 判断连通的时候,只要判断根节点数为1即可。 不多说,简单题,上代码。 上代码。 #include <stdio.h>#include <string.h>int k,flag[100005],bin[100005];int find(int x){    if(bin[x] == x)  return x;    return bin[x] = find(bin[x]);}void merge(int x,int y){    int fx,fy;    fx = find(x);    fy = find(y);    if(fx != fy)        bin[fx] = fy;    else        k = 0;}int main(){    int i,j,n,m,cnt,p;    while(scanf("%d%d",&n,&m) != EOF && n != -1)    {        if(n == 0)        {            puts("Yes");   &nb......

阅读全文(3599) | 评论:1

prim算法(2009-07-27 10:24:00)

摘要:昨天做了ZOJ1372,挺开心的,又学了一个算法——最小生成树的prim算法。 其实这个算法跟最短路径算法差不了多少,只是其中改了一点点条件。 这样说吧。比如最短路的起点是1号点,那么数组每次更新的都是到1号点的最短距离。 而最小生成树则是到已选的当前点集的最短距离。 两个都是贪心算法的经典。 学的不多,不过每天都在快乐地进步。 上代码:#include <stdio.h> #include <string.h> int mat[55][55],used[55],min[55]; int p; int prim() { int i,j,k,q,ret = 0; for(i = 1;i <= p;i++) min[i] = 1000000000,used[i] = 0; min[1] = 0; for(i = 1;i <= p;i++) { k = -1; for(j = 1;j <= p;j++) if(!used[j] && (k == -1 || min[j] < min[k])) k = j; used[k] = 1; ret += min[k]; for(j = 1;j <= p;j++) if(!used[j] && mat[k][j] && mat[k][j] < min[j]) min[j] = mat[k][j]; } return ret; } int main() { int i,j,n,r,a,b,c; while(scanf("%d%d",&p,&r) != EOF && p != 0) { memset(mat,0,sizeof(mat)); for(i = 0;i < r;i++) ......

阅读全文(4485) | 评论:0

今天学了优先队列(最大堆)(2009-07-20 10:06:00)

摘要:昨天去做了浙大的月赛。身为ACM菜鸟中的菜鸟的我,简直是被虐。 一个下午只看了一题。ZOJ3230,想了一下午只能想到M*N算法,还想了N种剪枝。 后来想想真是异想天开了吧。哎,一百万次的循环已经够呛,还想要有10000*100000的循环。 第二天看了一下最大堆的,又想到昨天Nineright所讲的C++中有优先队列的模版。 于是用了一下,对a排了个序,Ac了。 代码如下:   #include <stdio.h>#include <queue>#include <stdlib.h>#include <algorithm>using namespace std; struct s{    int a;    int b;}pr[100005]; int cmp1(struct s a,struct s b){    return a.a < b.a;} int main(){    int n,m,i,j,k,p;    while(scanf("%d%d%d",&n,&m,&p) != EOF)    {        for(i = 0;i < n;i++)            scanf("%d%d",&pr[i].a,&pr[i].b);        sort(pr,pr+n,cmp1);        priority_queue <int> q;        q.push(0);      ......

阅读全文(2768) | 评论:1