08 2012 档案

摘要:从刚开始接触背包到现在,已经快两个月了,学完背包之后就又继续学其它东西,现在该回头再来复习一下,整理整理自己的思路,使自己对背包更熟练一点,这里自己先复习一下0/1背包和完全背包。 0/1背包的主要思路就是:这件物品,取还是不取。用一个二维数组dp[i][v]来表示对第i个物品,背包容量为v时的情况。c[i]表示第i件物品的体积,w[i]表示第i件物品的价值。那么考虑第i件物品取与不取:如果不取,那么就可以转化为i-1件物品、容量仍然为v、价值没有增加的情况(dp[i-1][v]);如果取,那么转化为i-1件物品、容量减去第i件物品的体积后剩余容量、价值加上第i件物品的价值后的情况(dp... 阅读全文
posted @ 2012-08-30 10:37 等待电子的砹 阅读(1025) 评论(0) 推荐(0) 编辑
摘要:这是一道在无向图中求割点的题,还是利用了tarjan。而割点需要满足的条件是:若u为根节点,u至少有两个子节点;若u不是根节点,那么它至少有一个子女w,从w出发不可能到达u的祖先,即low[w]>=dfn[u]。(Low[w]为w或w的子树中能通过非父子边追溯到的最早的节点,dfn[u]为u的深搜被遍历到的顺序。) 把它放在这里可以当作模板来参考,用数组map存储图,recrd标记是否满足low[w]>=dfn[u],sonTree记录子节点的个数。#include<stdio.h>#include<string.h>#include<stdbool. 阅读全文
posted @ 2012-08-24 15:58 等待电子的砹 阅读(308) 评论(0) 推荐(0) 编辑
摘要:这是一道Tarjan算法求强连通分量的题。方法是将强连通分量缩为一个点集,找出出度为0的点(或点集),值得注意的是,答案是存在于1个点集之内,如果存在两个点集合,那么它们就是互相可达的,于是又属于一个强连通分量,所以也应该缩为一个点集。 由于数据量比较大,内存有限制,所以使用邻接表而不是邻接矩阵。由于以前觉得邻接矩阵比邻接表好写,所以对于邻接表只是略微的了解了一下,这次是第一次写邻接表,所以走了许多弯路:在节点的遍历上,我专门写了一个函数来判断两个节点之间有没有路,由于tarjan函数和求出度的时候都会用到,所以大量的函数调用造成了TLE;对于head数组,开始开的是一维,所以又写了一个... 阅读全文
posted @ 2012-08-21 14:59 等待电子的砹 阅读(552) 评论(0) 推荐(0) 编辑
摘要:这是一道tarjan算法(求一个有向图的强连通分支)的应用,这道题主要用于熟悉tarjan算法。题意是说有一些学校,每个学校都有一个list,比如a学校的list有b,c,那么a拿到一种软件后会分享给b、c(b拿到不会给a,如果a不在b的list上的话,c也是这样),所以就建成了一个有向图。问(1)至少给几个学校能够确保所有学校都能够拿到软件;(2)至少在某些list上添多少学校,可以确保任意给一个学校软件,所有学校都能拿到。 思路大致是,利用tarjan算法得到有向图打强连通分支,把它们全部看作一个节点,那么最后显然应该给所有出度为0的节点软件,第一个问题得以解决,同时,这样做之后,图... 阅读全文
posted @ 2012-08-18 18:44 等待电子的砹 阅读(369) 评论(0) 推荐(0) 编辑
摘要:这是一道差分约束系统的题目。所给的约束条件是对于一个序列的子序列来说,子序列的和大于或小于一个数,问是否存在一个序列,使得所有约束条件全部成立。 我采用用数列中类似于数列求和的方式,比如序列a1,a2,a3....令s1=a1,s2=a1+a2,s3=a1+a2+a3...为了方便,我还引入了s0=0,这样就可以根据题目的条件列出不等式,再把不等式转化为求最短路的问题。开始我想当然地认为si>=si-1(i和i-1为下标),加了这个条件之后当然是错的,后来发现了这个问题,将其去掉,但是却忽略了一点:这道题其实是让我判断是否存在负环。因为图可能不连通,所以应该每个点都要作为一次起点,用SP 阅读全文
posted @ 2012-08-17 19:36 等待电子的砹 阅读(437) 评论(0) 推荐(0) 编辑
摘要:这是一道差分约束系统的题,刚开始学,还有些地方不是很清楚,靠这道题弄清了一些问题。这道题是是说有一队奶牛要吃饭,有些奶牛互相讨厌,必须至少相隔一定的距离;有些奶牛互相吸引,距离不能大于一个定值。另外,这些奶牛可以处在同一个位置。求这队奶牛最远的长度。 拿题目的数据来说(1,3,10)、(2,4,20)、(2,3,3),很容易得出不等式:x3-x1<=10;x4-x2<=20;x3-x2>=3。并且,由于奶牛顺序不能改变,所以Xi>=Xi-1(i-1是下标)。我们可以把不等式变形为:x2<=x1+5;x3<=x1+10;x2<=x3-20。从而转化为求最 阅读全文
posted @ 2012-08-16 16:27 等待电子的砹 阅读(386) 评论(0) 推荐(0) 编辑
摘要:这是一道简单的KMP求next数组的题,几乎不用动脑筋,可以用来练练手,直接把两个字符串连接在一起求next就行了,唯一要注意的就是长度不能大于原来任一字符串的长度,如果长度大于了,要选择len1和len2中较小的一个输出。#include<stdio.h>#include<string.h>#define MAX_STR 50005char str1[MAX_STR*2],str2[MAX_STR]; int next[MAX_STR*2];void get_next(int,int);int main(){ char oupt[MAX_STR]; while(sca 阅读全文
posted @ 2012-08-13 21:05 等待电子的砹 阅读(516) 评论(0) 推荐(0) 编辑
摘要:这道题是考察对next数组性质的应用。题意相当于是求一个长字符串中循环节的个数。 由于我们知道next数组中存的是一个位置(假设next[j]的值为k,对应的字符串为M,如果k>0,那么M[0....k-1]和M[j-k.....j-1]是相同的,并且0...k-1这个序列一定是最长的),比如a b c a b c d(next值:-1 0 0 0 1 2 3 ),由next[6]=3可知,M[0..2]=M[3..6],这就找到了循环节,于是我们思考从next数组作为切入点,来找到一种方法来求得循环节的个数。 看看next数组的一个性质:next始终是从-1开始增加(在变为0之前)。. 阅读全文
posted @ 2012-08-13 10:56 等待电子的砹 阅读(695) 评论(0) 推荐(0) 编辑
摘要:一道KMP算法的基础题,用于熟悉KMP算法和求next数组,关于KMP算法,为自己写了一篇总结。 这道题要注意的是,模式串可以重叠,比如给出ACA与ACACACA,应该出现了3次,这里只需要在KMP的函数里稍微改动一下即可:如果模式串的位置等于了模式串的长度,说明模式串已经被完整地匹配了,并且,此时模式串的位置由于等于了长度,所以这里是并没有字符的,但next值会存在(详情见求next数组的值的函数),此时只需要假设它们不匹配,转到此时的next值即可。#include<stdio.h>#include<string.h>#define MAX_WORD 10005#d 阅读全文
posted @ 2012-08-11 17:01 等待电子的砹 阅读(134) 评论(0) 推荐(0) 编辑
摘要:KMP算法开始学的时候很不好理解,自己写了篇总结一下放在这里,使自己的思路清晰一下。 KMP算法之所以能够以o(m+n)(m为模式串长度,n为匹配串长度)的复杂度完成字符串匹配,是因为KMP算法不同于朴素的算法要进行匹配串指针的回溯。举个例子,对朴素的算法,如果要在”aadadefgadk“中匹配"adk“,首先比较"aad"与"adk",发现不匹配,然后再比较"ada"与"adk",考虑一种极端情况"aaaaaaaac"(有8个a)与"aaaaaaac"(有7个a 阅读全文
posted @ 2012-08-11 16:45 等待电子的砹 阅读(1453) 评论(0) 推荐(2) 编辑
摘要:这是一道二维的树状数组。与一维不同之处在于更新和求和都多了一重循环:更新:void update(int a,int b,int val){ int i,j; for(i=b;i<=lmt;i+=lowbit(i)) { for(j=a;j<=lmt;j+=lowbit(j)) { c[i][j]+=val; } }}求和:int get_sum(int a,int b){ int i,j,sum=0; for(i=b;i>0;i-=lowbit(i)) { for(j=... 阅读全文
posted @ 2012-08-10 10:16 等待电子的砹 阅读(144) 评论(0) 推荐(0) 编辑
摘要:一道树状数组的应用题,和POJ 3067非常类似,这道题是求比自己强壮(e更大,s更小)的牛的数量。 将POJ 3067的思路应用到这道题上,如果先对e按照降序排列,每加入一只牛,当前已经加入树状数组的牛的s如果比这只牛小,那么那些牛就更强壮,所以同样是在树状数组里的求和问题。同样,对s的排序规则关系到e相同时的情况,由于s更小就更强壮,所以先把s小的加入,于是s就按照升序排列。再考虑e和s都相同的情况,假设有一些牛的e和s都相同,为cow1,cow2.....,cowK,那么更强壮的牛的数量x,满足cow1=cow2=....=cowK=x。所以遇到e和s都相同的状况时,只需要复制答案... 阅读全文
posted @ 2012-08-09 14:59 等待电子的砹 阅读(422) 评论(0) 推荐(0) 编辑
摘要:这是一道运用树状数组的题。大意是求直线的交点数,前提是交点只能有两条直线相交,不能出现三点交于一点的情况。需要注意的是就是排序的规则。 假设东海岸的城市坐标为x,西海岸的城市坐标为y,当有一条公路(x1,y1)时,再修一条公路(x2,y2)与(x1,y1)相交,显然,当(i)x2>x1且y2<y1或(ii)x2<x1且y2>y1时,两条公路才会有交点,由于此时x,y有两个变量,都在变化,不好思考,不妨将y按照降序排列。那么,当有一条公路(x1,y1)时,需要再修一条(x2,y2),由于此时y已经按照降序排列了,所以y2<=y1.当y2<y1时,如果此时x2& 阅读全文
posted @ 2012-08-09 14:38 等待电子的砹 阅读(212) 评论(0) 推荐(0) 编辑
摘要:这是一道树状数组的基本操作题,熟悉树状数组的更新操作和求和操作。题意是求对一个坐标 (X,Y),求 (x,y)的个数,其中x<=X,y<=Y。由于坐标按照y的升序给出(如果y相同,又按x的升序给出),所以这里只用得着x一个坐标,每得到一组坐标(a,b),就求x坐标小于等于a的星星个数,再将坐标为a的星星个数更新(加1)。 另外,为防止x=0在lowbit()中造成死循环,每次得到x坐标都应该加1.#include<stdio.h>#include<string.h>#define MAX_STAR 32010 int n,c[MAX_STAR],level[ 阅读全文
posted @ 2012-08-08 17:23 等待电子的砹 阅读(162) 评论(0) 推荐(0) 编辑
摘要:这是一道树状数组的应用题,题意是要对一个序列按升序排序,每次交换相邻两个数,求交换次数。假设a,b,c相邻,如果a>b,a>c,那么a,b就应该先交换一次,a和c再交换一次。所以这道题就抽象为求逆序数,即对每个i,找到a[i]的左边比a[i]大的数的个数,求出总和。由于树状数组可以很方便地求出一个数左边比它小的数的个数,所以进一步转化为:对每个i,找到从a[i]开始,到最左边小于等于a[i]的数的个数,然后用i减去这个数,就得到a[i]左边比a[i]大的数的个数。 具体来说,就是维护一个数组(c[]),初始化所有值为0,对需要统计逆序数的序列,从左向右依次加入序列中的点,比如序列a 阅读全文
posted @ 2012-08-08 16:00 等待电子的砹 阅读(115) 评论(0) 推荐(0) 编辑
摘要:一道线段树的区间修改题,给区间染色,最后输出一个区间的颜色种数,由于颜色不会超过30种,所以可以用int型二进制的每一位表示一种颜色,比如颜色1就是000……0001,颜色3是000……100,那么一个区间内如果有两种颜色A和B,管辖这两个区间的大区间的颜色就为 A|B,最后根据查询到的数得出二进制中1的个数,从而判断出有几种颜色。 写这道题的时候,swap函数出现了一个错误: swap(int *a,int *b) int *c if(*a>*b) *c=*a; *a=*b; *b=*a; 这暴露出我的C语言基础还不扎实,开始声明*c的时候没有赋值,后来又要对... 阅读全文
posted @ 2012-08-08 09:08 等待电子的砹 阅读(223) 评论(0) 推荐(0) 编辑
摘要:一道线段树的区间修改题,和POJ3468非常类似,都是利用lazy-tag来加快速度,lazy-tag在poj 3468的解题报告中有说明。不同之处在于这里是更改stick的类型,所以对tag直接赋值就行了。另外,初始的stick为1,所以在建树的时候需要注意。#include<stdio.h>#include<string.h>#define MAX_HOOK 100005struct node{ int left; int right; int sum; int tag;}stick[4*MAX_HOOK];void build(int,int,int);voi.. 阅读全文
posted @ 2012-08-07 19:03 等待电子的砹 阅读(226) 评论(0) 推荐(0) 编辑
摘要:一道线段树的区间修改题,以前写的线段树都是单点修改,这里用到了区间修改。我开始觉得单点修改和区间修改差不多,把区间内每个点进行一次单点修改就是区间修改了,这样虽是可行,但是时间复杂度却大大增加,想想看,一个点一个点地修改,这和暴力有什么区别呢。 在网上找了好多资料,终于弄明白了用lazy-tag(lazy标记)进行区间修改。我的理解是这样的,为了减小修改次数,先将要进行的修改存起来,当访问到子节点的时候,如果发现父节点带有标记,就顺便将子节点更新,就像搭顺风车一样。在这道题中,每次可能要对一个区间加上一个值,比如全集为[1,7],现在要对区间[1,4]进行操作,例如要将[1,4]每个值都... 阅读全文
posted @ 2012-08-07 17:03 等待电子的砹 阅读(132) 评论(0) 推荐(0) 编辑
摘要:这同样是一道线段树的入门题,与HDU 1166非常类似,都是了解其基本的操作。不同是这一道是求最大值,所以query的操作略有不同。值得注意的是,节点数应该为题目所给的MAXN*4(HDU 1166也是)。这一点我还没明白是为什么。 #include<stdio.h>#include<string.h>#include<stdlib.h>#define MAX_STUDENTS 200002#define INF 1000000struct node{ int left; int right; int max;}studnt[MAX_STUDENTS*4]; 阅读全文
posted @ 2012-08-06 11:33 等待电子的砹 阅读(336) 评论(0) 推荐(0) 编辑
摘要:这是一道线段树的入门题,用于学习基本的线段树的建树、更新、访问的操作。只在这里说说基本的操作。 首先是建树(void build(int root,int le,int ri)),采用递归的方式:root为当前节点,le为区间的左端点,ri为区间的右端点;如果le==ri,说明此时长度为1,建到最底层了,所以返回;否则,建立左子树和右子树,显然左子树在数组中的下标为2*root,右子树为2*root+1,这时还要将区间一分为二,左子树负责[le,(le+ri)/2]的部分,右子树负责[(le+ri)/2+1,ri]的部分。另外一个操作是更新(void fix(int root,int l... 阅读全文
posted @ 2012-08-06 10:36 等待电子的砹 阅读(162) 评论(0) 推荐(0) 编辑
摘要:并查集应用,只要会做POJ2492,这道题也没什么问题了,也是利用偏移量解题,注意的是,为了方便起见,relation[x]=0表示x与x的根节点的关系是同类,relation[x]=1表示x被x的根节点吃,relation[x]=2表示x吃x的根节点。所以读入kind的时候应该改一下。另外,x吃x才算错,所以数据如1 5 5是正确的。有关偏移量,在POJ 2492的解题报告中有详细的说明,由于这道题POJ只有单组数据,所以while scanf()!=EOF应该去掉。#include<stdio.h>#define MAX_ANIMAL 50010int get_root(int 阅读全文
posted @ 2012-08-04 16:47 等待电子的砹 阅读(225) 评论(0) 推荐(0) 编辑
摘要:这是一道并查集应用的基础题,关键是靠这道题理解偏移量,gender[x]表示x节点与根节点的关系,0表示同属性,1表示不同属性,每次得到一组数据,首先判断它们的根节点是否相同,如果不同,则合并,如果相同,则判断它们与根节点的关系,如果它们与根点的关系相同,那么它们之间的关系也相同,则找到了suspicous bug. 解题的关键就在于对偏移量的理解,首先考虑合并集合,即函数unon().x的根节点为a,y的根节点为b,要合并这两个集合,就应该更新a与b的关系,由于已知了x与y的关系(题目每给出一对虫子,如果它们不属于一个集合,则说明它们关系为1,现在应该合并它们所在的集合),所以能得出g... 阅读全文
posted @ 2012-08-04 11:37 等待电子的砹 阅读(203) 评论(0) 推荐(0) 编辑
摘要:这是又是一道01背包的变体,题目要求选出一些牛,使smartness和funness值的和最大,而这些牛有些smartness或funness的值是负的,还要求最终的smartness之和以及funness之和不能为负。 这道题的关键有两点:一是将smartness看作花费、将funness看作价值,从而转化为01背包;二是对负值的处理,引入一个DELTA来表示“0”,这里的DELTA一定要大于每一个smartness的绝对值,另外在遍历cost[]的时候如果cost[i]>0,显然时从开的数组的最大值MAX_LMT开始往下减,如果cost[i]<0,则是从0(是0,不是DELTA 阅读全文
posted @ 2012-08-01 22:31 等待电子的砹 阅读(592) 评论(0) 推荐(1) 编辑