Friday, November 09, 2007

Oops! Blogger available again!

Oops! Blogger and Google Page available now (in China)... I have suspend my post working for a long time~ :)

My first post to celebrate blogger come in china, would be an introduction of DevExpress and Rapture.

Since I have to use C# in company, I learned some interesting work from C# guys. DevExpress is the fantastic one! Here is the demo picture of DevExpress, check it and u will love it:





A new concept of GUI application, Ribbon comes, maybe Microsoft Office was the first guy introduced it. Instead of menus, Ribbon is provide a new vision of user experience. Here is the common structure of Ribbon:

Ribbon Page 1<-->* Ribbon Page Group 1<-->* Ribbon Button Group 1<-->* Ribbon Button

Quite similar to menu system, which has menu bar, menu list, menu item...

Rapture is a Screen Capture Tool that is developed by Raymond, me.. :) . To remember my first company, Hanna Strategy Ltd. , which would be closed next year.
Get Rapture from my gPage

It's only work for Windows, since I use MS C#, maybe one day I would migrate it to Mono C#.

  1. Start it, and got notify icon.
  2. Double click it to start Region Rapture, or right mouse click it to see the menu.
  3. When u are capturing, click the right mouse button or press enter to finish the job.
The most important feature of Rapture is multiply regional capturing, which allowed u capture several regions at one time.

Thursday, August 02, 2007

[转]Firefox 3/4 的最新新闻

Firefox 3.0的开发代号为"Gran Paradiso",按照Mozilla基金会的计划,Firefox3.0将于2007年三季度正式推出。与现有的2.0不同,Firefox 3.0采用了全新的Gecko 1.9渲染引擎,这也是Firefox 3.0解决资源占用率高的关键。相比Firefox 2.0所采用的Gecko1.8引擎,Gecko 1.9在图形架构方面有了根本性的改变。Gecko 1.8采用传统的gfx图形架构,它是一种软件方案,由CPU来完成对2D图形图像的渲染;而Gecko 1.9改用"Cairo "图形架构,Cairo可以借助GPU来负责渲染2D图形图像,相当于实现网页渲染的GPU硬件加速,这样,CPU就被完全解放出来。由于现在的GPU普 遍都拥有非常强劲的硬件效能,承担网页渲染任务会非常轻松,因此从理论上说,Gecko 1.9引擎既可以实现更快的渲染速度,又能够大幅度降低CPU资源占用率,实现真正意义上的飞跃。

作为系统应用的基础构件,Cairo提供了一个稳定的用户层API,它可以提供现代化的图形处理管理能力,例如绘制与填充、映射转换、合成以及改 变Alpha半透明效果、高清晰文本显示等等,并且能够在不同的媒介上实现相同的显示输出。这个概念并不难理解,简单点说,它与OpenGL、 DirectX等图形API实际上是类似的东西,只不过OpenGL和DirectX属于3D加速的API,它们都可以让应用程序直接与图形硬件紧密地协 作;而Cario则是针对2D图像绘制的API,它向更高级的应用程序提供了一系列的图形处理功能,同时又借助OpenGL API实现与图形硬件的互动(Cario与OpenGL的衔接由Glitz函数库完成)形成,借助GPU的运算能力来处理2D图像相关的应用。那么,如果 我们将Cairo作为应用程序的图形架构,这个应用程序所涉及到的所有图像处理任务都可以由GPU来完成,在这一方面,专用化的GPU显然要比通用的 CPU更具效率。这样,应用程序不仅可以实现更丰富、更复杂的图像效果(如抗锯齿、半透明、阴影、映射转换、变形等等),同时还能在低CPU占用的前提下 保证流畅的运行。

除了这些原本就有的后端外,Cairo的后端还包括pdf、svg等,分别可对pdf格式和svg格式提供原生支持,这将能显著提升pdf文件和svg矢 量图形的渲染速度。现有PC还缺乏这样的能力,不论你拥有多么强劲的CPU,在浏览pdf文件或者放大缩小svg 矢量图形时都会感觉到显示的停滞感。但如果你的图形系统基于Cairo构建(例如Gnome),并且拥有一块主流性能的3D显卡,执行pdf、svg相关 操作将会变得非常流畅,从而有效提升用户的使用体验。显然,基于Cairo的Gecko 1.9渲染引擎也可以获得相同的效果,如果你直接在Firefox 3.0浏览器中打开pdf文档或者svg矢量图形,内容渲染速度将大大快于以往,并实现真正意义上的同步显示。

实现Gecko与Cairo的融合是一项费时费力的工作,开发者并没有试图一下子将Gecko的图形架构完全转为Cairo,而是以模块化的方式 循序渐进地进行。事实上,早在Gecko 1.8/Firefox 1.1版本中,开发者们就着手Cairo的整合工作,如Cairo中的Canvas、SVG矢量图支持模块已经在Gecko 1.8中实现,而非Cairo的SVG实现方式(例如GDI+)仍得到保留,另外Gecko 1.8/Firefox 1.1的Windows版本也没有实现SVG功能。另外,GPU硬件加速功能也没有在Gecko 1.8中实现,依然只能通过软件的方式进行页面内容渲染。基本上,Gecko1.8只是实现最初级的Cairo整合, 图形架构仍然是基于2D的gfx API。除了Firefox 1.1外,后来的Firefox 1.5和现在的2.0版本也都是采用Gecko 1.8引擎,这三者的差异更多在浏览器外壳以及对安全功能的增强。

Adobe公司并未考虑通过加大技术力量来解决这一问题,而是采用一个十分英明的办法,将Flash源代码直接捐赠给Mozilla基金会,这也 是Mozilla基金会有史以来收到的最大一次代码捐赠。Adobe表示未来将把最新的Flash源码直接提供给开源业界,以实现未来浏览器与Flash 播放功能的更佳整合。有鉴于此,Mozilla基金会决定建立一个名为"Tamarin"的新项目,专门用来管理使用Adobe所贡献的代码,而新项目将 由Adobe与Mozilla共同管理监督,相关源代码将被下一代"SpiderMonkey (Gecko的JavaScript脚本引擎)"直接整合。除了贡献Flash源代码外,Adobe还将向Mozilla基金会提供 "ActionScript Virtual Machine(简称AVM)"虚拟机软件,该软件是Flash Player播放器中的一部分,它的功能就是负责对ActionScript代码的解释。ActionScript是Adobe Flash产品平台的脚本解释语言,该语言可以实现Flash中内容与内容,内容与用户之间的交互,目前它的最新版本为3.0。与广泛使用的Java Script和微软Jscript一样,ActionScript完全符合ECMA International的ECMAScript标准。

Firefox的锐意进取将给对手带来前所未见的压力,显卡加速网页浏览即将进入现实,而Firefox将无可争议成为最快的浏览器。微软将首当 其冲面对这些压力,显然微软不会打算以IE 7.0应战,但IE 8.0似乎还没有将显卡加速渲染功能考虑在内,那么它就很难有效遏制Firefox 3.0/4.0对市场的进一步蚕食。Opera同样将大受影响,它一向被认为是浏览器家族族 中的速度冠军,在Firefox 3.0出现之后Opera很可能将失去光环。同样遭受Firefox3.0/4.0技术冲击的还有Konqueror,目前KDE项目组正在向KDE 4.0发起冲击,Konqueror也将升级到4.0版(KDE 4.0计划于07年第四季度推出),但Konqueror 4.0同样来不及增加显卡加速渲染功能,它的重点更多会放在W3C新标准新技术的支持方面。至于苹果的Safari,过去它一直采用Konqueror的 渲染引擎,现在苹果打算与Konqueror分道扬镳自行发展,缺乏开源支持的Safari要实现网页3D加速就更加困难。对整个开源来说, Firefox 3.0/4.0标志着自由软件开始在技术上超越商业软件,而伴随着开源阵营的日益壮大,这样的事情未来将会越来越多。令人愉快的是,自由软件与商业软件并 非迥然对立,两者已经开始进行紧密的合作─Adobe贡献源码、微软支持XEN莫不是如此。

Tuesday, July 10, 2007

n多ubuntu发行版

ubuntu确实满疯狂的:

Ubuntu 主力发行版,基于Gnome桌面环境
Kubuntu 基于KDE桌面环境
Xubuntu 基于Xface桌面环境
Edubuntu 用于教育目的的发行版
Fluxbuntu 基于Fluxbox桌面管理器
Elbuntu 基于E17桌面管理器
nUbuntu 安全性至上
Hiweed 中文环境至上
Dubuntu 同样是针对中文用户
Ubuntu CE 基督教徒专用
Ubuntu ME 回教徒专用
Ubuntu SE 魔鬼用ubuntu
Ubuntu Studio 多媒体工作环境
Scibuntu 某科学家的科学家版本
Impi Linux 针对非洲的ubuntu
zSeries Ubuntu 针对IBM主机的ubuntu
Ubuntu Ultimate 有个家伙居然想搞ubuntu终极版
Linuxmint Ubuntu盗版

Sunday, July 08, 2007

2007年7月第一周

第一周上班,好累,知道赚钱的不容易了~,周末在Ubuntu论坛上逛了一圈,发现不少扯谈,分享一下:

网络操作系统:plan 9

Linus高调回应微软专利侵权指责
(当我第一次听到微软这事的时候,我的第一反应是~微软好假)

基于 Windows 的 Ubuntu 安装程序
(邮购,刻盘,现在又多了一种spread ubuntu的方法了)

世界上第一辆开源汽车

Google连续两年成为全球最有价值的商标


在公司用windows,而且公司走的是保密路线,任何代码/资料都不准带出公司,任何移动设备都不准带入公司,除了带入和带出的限制,还有一个倘若离开了项目组,不准滞留任何和原项目相关的任何资料的限制~ OMG

在家里使用ubuntu(上班的这一周,还没进过win),宣扬个性和民主,呵呵,整个人就像双重人格一样了~~
不过这样也好,至少公司用正版软件,家里用开源的,我是遵纪守法的好公民。

我很喜欢这份工作,我当初找工作的时候投了两类公司,一类是很有名的(谋生类),另一类就是建模软件的公司(兴趣类),虽然有一家建筑软件公司因为我没有 建筑的背景所以没给我二面的机会。我从小就喜欢玩模型玩具(拼飞机阿,轮船阿,四驱车阿,还有高达机器人(很贵)),很喜欢拼装成功的感觉,所以大一就选 了3DMAX,很喜欢三维的东西。

公司也不错,一周里许多公司上层都作了讲座,算是认识了吧。知道公司很年轻,但已经有相当的规模了,为了跟上这个规模,公司提供了许多给员工发展的空间。而且公司待遇满好,环境非常舒适,最让我印象深刻的是公司的厕所,豪华级别的~偶用过google、微软和IBM的厕所。。。都不及现在公司这么豪华。

同事大都是外地的本科生,公司总体上员工都很年轻,华中科技大学的人特别多~也许有特别去那里宣传过吧。其他的我有知道的是四川大学、成都大学、华东理工等等。

公司最让人头疼的一点是人多,上下班的时候电梯挤啊,吃饭的时候找个座位都很难。

Saturday, June 23, 2007

Ubuntu 7.04

“Ubuntu" is an ancient African word that means "humanity to others".

继firefox热潮之后,ubuntu今年开始热起来,可以说这款打着“为人民服务”旗号的操作系统,已经愈来愈受“人民”的欢迎了。现在已经出现了不少get Ubuntu的连接,而且 ubuntu的传播方式比firefox更疯狂(下载/邮寄+免费+鼓励传播的标语)。

头条是Dell表示将在几款机型上预装linux操作系统,而且选择的就是ubuntu这么一个非企业级别(至少和redhat/suse相比)的个人系统。可以参考该网站 http://www.dellideastorm.com/

Dell的问卷调查表示,有70%的人要求能在机器上预装l inux。在Dell确定了预装的计划后,ubuntu及一些linux的粉丝们便开始组织要求各大公司发布linux版本软件的需求,其中包括要求暴雪发布基于linux的星际2,要求google移植主要软件到linux平台等等。(网站我都没记,不好意思)

除了ubuntu本身的四套发行版,Ubuntu/Kubuntu/Xubuntu/Edubuntu以外,不少网友都在为ubuntu扩大阵容:
  • Wubuntu - ubuntu狂热fans写的基于web的模拟ubuntu环境的网站,用的都是js写的。
  • Hiweed & Dubuntu — 在ubuntu中文站看到的,不知道其目的是什么,可能就是一个发行包吧。
  • Medibuntu - 提供关于media的ubuntu包。
当然,ubuntu本身在7.04 里作了不少工作。ubuntu本身bug改了不少,感觉更加舒适稳定了。如果是邮寄ubuntu光盘的话,可以用win来运行光盘,可以看到ubuntu为win用户同样提供了一些win下的软件。果然是for human beings,即使是对头的用户也要服务,这种精神太伟大了(当然不排除抢客户的嫌疑-_-b),如果仔细观察的话,就可以发现,目前大量的开源软件都是同时支持win和linux的,而且有许多人是同时在使用win和linux的,我想这和linux包容的心态是分不开的,毕竟人不应该在一棵树上吊死,不然就死得太冤了(我也支持win的哦),多样化的世界才是多彩的世界嘛。

最后不得不谈的是ubuntu疯狂的传播策略,真的是钱多得用来砸人了。要获得ubuntu或其他发行版,可以通过免费下载,这是大部分linux采用的。而ubuntu还提供了免费邮寄的服务,可以在ubuntu的网站上直接申请少量的光盘,或者申请大量光盘(需要确定)。在上大,机器人协会就申请了500张光盘,Canonical尽还都是免费地寄过来了(-_-b, so cool)。同时,ubuntu每张光盘上会写到,请与你的朋友分享该光盘的字样。我就要求了10张光盘(送贴纸),其中有一些是重复的,也就是~你可以拿出去送人,汗,要ubuntu找我。

Thursday, June 21, 2007

Thursday, June 14, 2007

Netbeans的UML工具

今天差点被Netbeans的UML工具感动得哭了出来。从Netbeans4.0开始知道除了Eclipse还有一个这么好的IDE。虽然当时Netbeans离JBuilder和Eclipse还有很大的距离,但我一直十分坚持使用Netbeans,因为我从Netbeans身上学到的不光是使用一个IDE,更多的是做程序开发的思想。

记得那次我是写一个八数码的搜索算法分析的程序,用到了GUI,那时我发现在Label修改文本的时候可以有一个叫Resource Bundle的东西,于是我知道了Java的国际化,当时感叹啊。。。 于是呼,以后写程序坚决不在程序内直接放字符串常量,要么在头上声明个final引用,要么就Resource Bundle一下。

Netbeans的GUI编辑器是让我感动最多的地方,它的易用性给我减轻了很多的负担,使编程变得愉快而轻松。除了GUI编辑器以外,当时他的Web开发包也是让我感动死掉~,整合的Tomcat使得调式如此简便,就在当时我一再向周围的人推荐Netbeans,希望大家能把目光从Eclipse身上转移一点给Netbeans,但最后都是以失败告终。

后来Netbeans的合作开发包,虽然当时一直是对Eclipse的ECF感兴趣,但Netbeans的合作开发实在太先进了。还有JavaHelp等等,从Netbeans身上学了好多好多东西。

今天,为了在毕业设计里加几个UML图,尝试性地下载了Netbeans的UML工具包。哇!哭了,一上来就有三个选项:平台无关模型、Java模型、对Java项目做逆向工程。思路非常清晰,Java模型是主打,其他的仍然可以用平台无关模型。而我选择的是Java逆向工程,完美!把我那个项目所有引用到的类都解析出来了。然后使用使用看看,哦~~~太感动了,功能so强大。前一阵子在唠叨Poseidon For UML又慢又龊,于是乎去网上找了N个UML 开发工具,要么是付费的,要么就是太龊,而Eclipse的UML工具,建模没问题,只是图形开发环境得用最新的Eclipse,更新最新的满麻烦的。

以下这张UML,是我通过选中几个模型之后,自动创建的类图,然后稍加修饰的结果:


总之,Netbeans的UML工具智能化程度已经很高了,可能还不如一些收费工具来的厉害。但作为一款免费的IDE,免费的UML工具,已经是相当相当专业的。Sun不愧是开源的老大啊。

Friday, June 08, 2007

X over SSH

今天又学到一招,用ssh来图形远程登录。原本linux的图形远程登录比较熟悉的是vnc,但这次用ssh登录,比vnc快,而且犹如在本地运行一般。

可以用windows或linux登录有ssh server和x server的linux服务器。理论上,本地需要的是能运行x,及ssh客户端。

详细文档见此:X over SSH - A Tutorial

Wednesday, June 06, 2007

《为什么时光不能倒流》推荐

终于看完了。我一共参加过三次ACM/ICPC的比赛,另外有一次是在本校组织的地区赛。很幸运,四次都见到了CJ教授,而第五次则是CJ教授到学校里来宣传书的那一次。感觉教授有点嬉皮,很能调节气氛,就这一点算是个满讨人喜欢的教授。

昨天晚上睡不着,有点头疼(疼了有一段日子了),再加上蚊子嗡嗡的折磨,更加令我难以入睡。于是,捧起CJ教授的书,本打算是用作催眠的,却没有想到直到凌晨3点才有意识到太晚了。

《为什么时光不能倒流》宛如一碗鸡汤,滋补着我的心灵。拿到书的第一反应是惊讶CJ教授传奇的人生经历,而后从感动到感悟,每个故事都给了我一个人生的哲学。




今早起床,只睡了6个小时,但却额外精神,头不疼了,咦?真是有点奇怪哈,难道是心灵治愈了,身体就可以自然地治愈么。乘着头还没开始疼,赶快读完了书的剩余部分,确实是被感动了。这是一本适合年轻人,特别是那些儿时还是充满了憧憬和幻想,而现在却是忙忙碌碌,只是忙碌地不再是为了儿时所有的美好愿景的人,停下片刻,细细品味的美味鸡汤。

Tuesday, June 05, 2007

Stoer-Wagner算法

Stoer-Wagner算法是用来计算无向图的全局最小割的,理论上复杂度可以为O(|E|+|V|log|V|)。我的实现不是最好的,但觉得还行吧。

网友的好文章:最小割Stoer-Wagner算法

题目是百度06年的复赛题,星球大战。可以在POJ上练习,POJ2914。

相关论文和偶的代码,可点此下载

Stoer-Wagner算法的实现:


#include <iostream>
#include <algorithm>
using namespace std;

#define initSet(n,Arr) for(int i=0;i<n;++i)Arr[i]=i;
#define MAX 1<<30;
int graph[600][600];

// Stoer-Wagner Algorithm
int globalMinCut(int n){
// A is A set for Stoer-Wagner Algorithm
bool* A=new bool[n];
// V is vertex index
int* V=new int[n];
int* W=new int[n];

initSet(n,V);

int best=MAX;
while(n>1){

//the most tightly connected vertex.
int maxj=1;

// initialize set A and other vertex's weight
A[V[0]] = true;
for(int i=1; i<n; ++i){
A[V[i]]=false;
W[i]=graph[V[0]][V[i]];

if(W[i]>W[maxj])
maxj=i;
}

// find a min-cut
int prev=0,buf=n;
while(--buf){
// add it to A
A[V[maxj]]=true;

if(buf==1){
// update min cut
best=min(best,W[maxj]);

// merge prev and last vertex
for(int k=0; k<n; ++k)
graph[V[k]][V[prev]]=(graph[V[prev]][V[k]]
+=graph[V[maxj]][V[k]]);
V[maxj]=V[--n];
}
prev=maxj;
maxj=-1;

// update the weights
for(int j=1; j<n; ++j)
if(!A[V[j]]){
W[j]+=graph[V[prev]][V[j]];

if(maxj<0 || W[j]>W[maxj])
maxj=j;
}
}
}

delete[] A;
delete[] V;
delete[] W;
return best;
}


int main(){
// n - vertex number
// m - edge number
int n,m;

while(scanf("%d %d",&n,&m)==2){
memset(graph,0,sizeof(graph)/sizeof(bool));

// v-w is an edge with c weight
int v,w,c;

while(m--){
scanf("%d %d %d",&v,&w,&c);
graph[v][w]+=c;
graph[w][v]+=c;
}

// output min cut
printf("%d\n",globalMinCut(n));
}
}


Saturday, June 02, 2007

百度之星2007初赛

HOHO,恭喜恭喜,上大的四人都过初赛啦! 我,梁老大,沈还有Jackie Yu。我和Jackie两天都做了,沈做了第一天,梁做了第二天。最后沈和梁晋级,我靠第一天晋级,Jackie靠第二天晋级。我第一天拿了30分(题1全过,题2过一半),比期望的低哦,最后的那道SQL本来希望能过两个CASE的,结果全挂了,555,沈也是用暴力解的,但他过了两个CASE,估计是我哪里细节出了问题,导致全错。第二天很郁闷,中午做题果然没晚上精神爽,直打瞌睡。第二天只做了两道(1,4),最后的结果是第1题只对了一个case, -_-b,超级郁闷,后来发现程序里少了两句判断,555,不然第二天也能晋级啦,现在只有9分,不过还好有第一天保底(只是对不住陈胖子了呀)。

题目可以见某网友的帖子,感谢他保留了百度试题:
http://www.ninstein.com/blog/article.asp?id=199
http://www.ninstein.com/blog/article.asp?id=202

其他的题目就不说了,百度有点评(第二天要准备trie的模板呀),我个人对第一天的第四题SQL的SELECT语句比较感兴趣,所以重新做了一遍:

基本上是做了两点的优化(较暴力法),一个是结构上加了索引,二是计算满足条件的几个集合的交集(在结构的基础上优化的求交算法)。

为了说明结构我画了图,还不错吧 ^_^


简单说明一下,该结构完全是为了针对题目而做的,我考虑下,为了实现Delete, Update还需要修正一下结构,而且结构改动后后面的Select算法也要调整。另外,Select是单向的,即只能由条件找出记录号,不能由记录号找出记录的所有信息,要实现的话应该在Record上再加一些变量。不管了,只是针对AND逻辑的嘛。

Table[i][j]的位置不是存放第 i 记录的第 j 字段值,而是存放一个指针,指向下一个与Table[i][j]值相同的记录号,也就是链表结构。索引表存放的才是字段值,对应一个startId是在Table中的第一个拥有该字段值的记录号,即链表的head。

假设,按图中sample有5条记录,0 1 3的c3字段值为a,2 4的c3为b。那么Select c3为a的所有记录,就是在IndexTable中找c3的字段索引,然后找对应的a的startid,得0。然后回表中开始找出所有记录,Table[0][c3]=1, Table[1][c3]=3, Table[3][c3]=-1。-1为终止,于是有 0 1 3 三条记录。

由上可以求出,满足某字段值的一个集合。第二步是求满足多个字段值的一个交集。由于结构本身提供了一个很有利的条件,即若Table[i][j]的字段值等于Table[i][k]且两者均不为-1,则Table[i][j]<table[i][k]当且仅当 j<k,算法描述如下:

(假设满足求n个condition的记录数count=0)
if condition is empty
count=recordNum, exit

准备一个索引数组tb,tb[i]代表 i 条件下的当前记录号。tb初始全-2。
foreach condition as ci
int tmp= IndexTable中ci条件的startid值,无法满足ci,则tmp=-1
if tb[ci] 已存在,即 !=-2
if tb[ci]!= tmp
count=0, exit
else
next condition
else
tb[ci]=tmp

依某算法(算法很多,自定吧)取字段c为主键,可以理解为取某个condition为主条件

while tb[c]!=-1
foreach condition as ci
if ci==c
continue
else
while tb[ci]<tb[c] && tb[ci]>=0
tb[ci] = Table[tb[ci]][ci] // next record
if tb[ci]>tb[c] || tb[ci]==-1
break;
if all condition matched
count++
else
tb[c]=Table[tb[c]][c]

count is result

复杂度分析: 空间复杂度上是不会亏的啦,字段值没有重复保存过,索引用的都是数字。设记录数n,字段数c,构造DB时的复杂度O(nc)。设某个查询的条件是q条,查询的复杂度min(q,c)+sum(count(qi)) min(q,c)是条件数和字段数取小者,qi表示第i个条件,count是满足i条件的记录数(可以缓存一下的),sum()为求和函数。

其他建议:取主键的算法很多(甚至可以不取,直接假设第一个条件对应的键为主键),可以单纯地用缓存过的满足条件的记录数来决定记录数最少的那个为主键。但对于复杂度不会有提高,因为如果按我上述的算法,复杂度是固定的,主键不影响复杂度。

存在不同主键的情况下会影响复杂度的算法,假设已经求到Table[i]是满足所有条件的记录,那么求下max(Table[i][cj]) cj为每个条件对应的字段,只有最大值对应的记录才有可能为下一条满足所有条件的记录,即使他不是满足所需要的记录,那么只要循着该字段一定能找到真正的下一条满足所有条件的记录。这种跳跃式的算法,可以有效减小复杂度。

缺点:结构只是针对select and做了优化,并没考虑太多,可能会不方便其他操作。优化中将记录标号了,虽然现在大部分表都喜欢加个id,但数据库本意是记录无序的。如我图中所画,DB有许多Table,而只有一个IndexTable,我的想法是一个IndexTable可以管理所有有关联的Table的所有字段,以优化做select and操作。但还没设计完,现在的IndexTable显然是不行的,以后有机会再说吧。

偶的代码(C++),大致实现了上面的结构和算法,测试数据使用MySQL 的sakila sample 的payment表,修正后的数据以及代码点此下载 (放在上大ACM论坛,-_-b荒废好久的论坛啊,只能用来摆摆文件了):



#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <utility>
#include <sstream>
#include <algorithm>
using namespace std;

// DB structs
// first is startId, second is len(len may be tempory used for other target)
typedef pair<int,int> Index;
typedef map<string,Index> FieldIndex;
typedef vector<FieldIndex> IndexTable;
typedef map<string,int> ColumnName;
typedef vector<int> Record;

struct DB{

// a table (since only one table provided)
string name;
vector<Record> records;
int recordNum,columnNum;
ColumnName nameMap;

IndexTable it;

DB(int n,int c):recordNum(n),columnNum(c){
records.resize(n);
it.resize(c);
for(int i=0;i<n;++i){
records[i].resize(c);
}
}
};

// Query structs
typedef pair<string,string> Expression;
typedef vector<Expression> Query;

// called while constructing the DB and IndexTable
int addValue(FieldIndex& index, string& value,int curIndex){
map<string,Index>::iterator iter=index.find(value);
int lastIndex=-1;

if(iter==index.end()){
index[value]=Index(curIndex,curIndex);
}else{
lastIndex=index[value].second;
index[value].second=curIndex;
}

return lastIndex;
}

void initDB(DB& db){
string buf;
// parse db name
cin>>db.name;
getline(cin,buf);

// parse column name
getline(cin,buf);
stringstream ss(buf);
string name;
for(int i=0;i<db.columnNum;++i){
ss>>name;
db.nameMap[name]=i;
}

// parse db records
for(int i=0;i<db.recordNum;++i){
getline(cin,buf);
stringstream ss(buf);

for(int j=0;j<db.columnNum;++j){
string value;
ss>>value;
db.records[i][j]=-1;
int lastId=addValue(db.it[j],value,i);
if(lastId>=0){
db.records[lastId][j]=i;
}
}
}
}

bool isExpression(string& str){
int len=str.length();
for(int i=0;i<len;++i){
if(str[i]=='=')return true;
}
return false;
}

bool validChar(char c){
return (c>='0' && c<='9') || (c>='a' && c<='z') || (c>='A' && c<='Z');
}

void parseExpression(string& str, Expression& exp){
int i=0,st=0,len=0;

while(!validChar(str[i]))++i;
st=i;
while(validChar(str[i]))++i;
len=i-st;

exp.first=str.substr(st,len);

while(!validChar(str[i]))++i;
st=i;
while(validChar(str[i]))++i;
len=i-st;

exp.second=str.substr(st,len);
}

int doQuery(DB& db,string& q){
int cnt=0;
stringstream ss(q);
string buf;
Query query;

while(ss>>buf){
if(isExpression(buf)){
Expression exp;
parseExpression(buf,exp);
query.push_back(exp);
}
}

if(query.empty())return db.recordNum;

int* tb=new int[db.columnNum];
fill(tb,tb+db.columnNum,-2);

for(Query::iterator iter=query.begin(); iter!=query.end(); ++iter){
int col=db.nameMap[iter->first];
map<string,Index>::iterator mapIter=db.it[col].find(iter->second);
if(mapIter!=db.it[col].end()){
int st=(mapIter->second).first;
if(tb[col]>=0 && st!=tb[col]){
return 0;
}else if(tb[col]<0){
tb[col]=st;
}
}else tb[col]=-1;
}

int lastValue=-1;
while(true){
int i=0,curValue=-1;
for(;i<db.columnNum;++i){
if(tb[i]==-2)continue;
if(lastValue>=0 && tb[i]==lastValue){
tb[i]=db.records[tb[i]][i];
}
if(tb[i]==-1)break;

if(curValue==-1){
curValue=tb[i];
}else{
while(tb[i]<curValue && tb[i]>=0){
tb[i]=db.records[tb[i]][i];
}

if(tb[i]>curValue || tb[i]<0){
break;
}
}
}
lastValue=curValue;
if(tb[i]==-1 || curValue==-1)break;
if(i==db.columnNum){
++cnt;
}
}

delete[] tb;
return cnt;
}

// main entry
int main(){
int c,n,q;
cin>>c>>n>>q;
DB db(n,c);
initDB(db);

string line;
while(q--){
getline(cin,line);
cout<<doQuery(db,line)<<endl;
}
}


Tuesday, May 29, 2007

07年5月29日 在复旦大学的topcoder比赛

先是匹萨,棒约翰的,还不错,我和肖各吃了两块,就饱了,其实是不太好意思吃多 ^_^

然后是比赛,感觉脑子的转速要比在家里做快得多,时间也貌似比一般的一个半小时长得多(因为单位时间的思考能力强了,所以感觉时间就多了)。算是三校联赛吧,被复旦踩是必然的,目标是踩东华。最后338.31,是room2的第7,divsion的第13,还是被两个东华的踩了。

很久没写tc报告了,因为很久不关心算法。但今天还是满有意思的,写一下,纪念一下:

总得来说DIV2的题目就是比较简单的呀。

problem 250:
一个Set包括0-9个数字,其中6和9可以互用,隐含的意思就是可以表示 66 或 99 或 69。
然后给个门牌号,问至少买多少Set能够摆出这个门牌号。

算法很简单,统计一下门牌号中出现过的数字个数。因为6和9可以互用,所以把6的个数和9的个数平均一下,有两个写法:


// method one, after counting
count[6]=count[9]=(count[6]+count[9]+1)/2; // forget add one will be chanllenged

// method two, in counting iteration
if(count[6]<count[9]) count[6]++;
else count[9]++;


看到两个人用第一种写法忘记+1,cha之~,HOHO,赚100分。

problem 500:
有金G银S铜B三种钱币,去银行转换的规则如下:
11 S -> 1 G
11 B -> 1 S
1 G -> 9 S
1 S -> 9 B
问从G1 S1 B1换到 G2 S2 B2的最少交换次数,或-1表示不可能

与其说是贪心,不如说是逻辑题,只要依存简单的逻辑,就能既保证代码清晰,又可保证准确率:
step 1. 如果B不够,只能用S换B
step 2. 如果G不够,只能用S换G
step 3. B和G都够了,若S不够,先用G换S,再用B换S。因为G换S一次可以满足的S多,所以先G换S。

5555,前面的代码都是好好的,可惜最后在B换S的地方,忘记减去B,加上S了。。。好粗心啊 >.<
一开始沈发现了,但他给的cha数据没能把我cha掉~,洋洋得意地笑沈时,忽然某人把我cha了~ 瞬间郁闷

problem 1000:
比赛的时候想了n套方案,结果还是没能决定用什么方法解之。
题目意思是给出一个序列,要求用最小的cost排序,将i放到某个值后面/前面,花费的cost是i。

大大的程序千奇百怪,有STL库牛人的,有搜索解的,有DP的,不过最欣赏的是这个解法:
可以把问题转换为, 求顺序的最大cost的序列,然后用总cost减一下就行了。

例如sample 中的 6 4 5 3 8 2 7 2 11 2 2,顺序序列可以是 4 5 8 11,也可以是4 5 7 11,对于一个顺序序列,剩余的部分便是待移动的数,为了保证待移动的数的cost尽可能小,就是保证顺序序列的cost尽可能大,所以取 4 5 8 11 的cost和为28,所以只需要用最少52-28=24来完成排序。按照这个思路,有程序:


public int calcMinimalCost(int[] arr){
int total=0,len=arr.length,maxCost=0;
int[] cost=new int[len];

for(int i=0;i<len;++i){
cost[i]=arr[i];
total+=arr[i];

for(int j=0;j<i;++j){
if(arr[j]<=arr[i] && cost[j]+arr[i]>cost[i]){
cost[i]=cost[j]+arr[i];
}
}
maxCost=Math.max(cost[i],maxCost);
}

return total-maxCost;
}

Tuesday, May 22, 2007

Portlet with Ajax Tech (Jetspeed)

I was required to upload a large file via portlet with the process message displaying in the client side, and ajax would be the best choice. In order to ease the job, prototype was included first, so that the Ajax instance would do me a great help.

I've referred so many articles about the ajax application in portal, mostly work for WebSphere Portal rather than Jetspeed, tomcat-based portal. At last, I solved this problem, and as a conclude, I found that the problem could be broken down into three problem:

  1. Understanding the principle of the ajax application in portal, JSR-168 would be the most helpful reference. And here is a well-spread diagram to show this principle:

    As JSR168 said, portlet session could share the data with servlet session, so render the page via portlet and request the update from servlet, which makes the ajax realizable. Here is the article where the above diagram from.

  2. Share the data between portlet and servlet. Of cause, there are some applications do not need the servlet and portlet bundled, there would be unnecessary to consider this problem in such cases. But as to my problem, portlet and servlet should bundled together. As the articles I have read, I found it maybe was not a problem for WebSphere, but it's really a problem for tomcat based portal. The solution was so easy, just configure the server.xml like this, I mean to add emptySessionPath="true" attribute:

    <connector port="8080"
    maxthreads="150" minsparethreads="25" maxsparethreads="75"
    enablelookups="false" redirectport="8443" acceptcount="100"
    connectiontimeout="20000" disableuploadtimeout="true"
    emptysessionpath="true" />

    And read this article to know what the session identifier do to make such tricky problem.

  3. Last work is to write the codes and test it. So the last problem is about the coding.
    Most of these coding barriers could be taken easily via careful reading JSR168 Spec. Such as, portlet and servlet share data in APPLICATION_SCOPE, so using APPLICATION_SCOPE to store session. Url and javascript debuging would also cost a lot of time.


A good article about Ajax with WebSphere Portal:
http://www-128.ibm.com/developerworks/websphere/library/techarticles/0606_bishop/0606_bishop.html?ca=dgr-lnxw03AjaxPortals

So, it's really fun to work with portal, especially that using the ajax tech to make the portal more vivid. Hope this article help you solve your problem, thanks.

Sunday, May 06, 2007

DataTypes in PostgreSQL

It's quit a different world of PostgreSQL from MySQL. Before I began to use PostgreSQL, I thought all the relational DB are the same, just be familiar with ANSI SQL, and everything will be done. PostgreSQL proved me that it's a ludicrous thought, as an advance object-relational DB, PostgreSQL has guide me a new idea of DB world. It's not just a dull warehouse,where I put and get, but an amazing technology that with so many smart and fashion thoughts.

I learned two new tips of PostgreSQL's datatype today:

First is a notational convenience for unique identifier columns. In other relational DB, I am so familiar with the command

CREATE TABLE sometable (some_id INT(8) AUTO_INCREMENT, PRIMARY KEY(some_id));

but it was replaced by a notational type -- SERIAL or BIGSERIAL, just like the serialization in Java :)

CREATE TABLE sometable (some_id SERIAL, PRIMARY KEY(some_id));

then it will equal to:

CREATE TABLE sometable (some_id integer NOT NULL DEFAULT nextval('sometable_some_id::regclass')
, PRIMARY KEY(some_id));

Click here to see more.

Another tip is more useful, it's about the enum type in PostgreSQL, (MySQL support Enum, as I know, but it was still convenient to simulate enum type in PostgreSQL):
Here is a good article about it.

Three methods available:
Both 1st and 2nd methods use check constraint to the field, while 3rd use foreign key
Both 2nd and 3rd methods define a new DataType.
As to me, I prefered 2nd.

1st:

CREATE TABLE average_temperature
(
year INTEGER,
temp REAL,
season TEXT (CHECK season IN ('spring', 'summer', 'autumn', 'winter'))
);


2nd:

CREATE DOMAIN season_type
AS TEXT
CHECK (VALUE IN ('spring', 'summer', 'autumn', 'winter'));

CREATE TABLE average_temperature
(
year INTEGER,
temp REAL,
season season_type
);


3rd: (since every value based on an integer key, it will be able to sort and compare values)

CREATE TABLE season_lookup
(
code INT PRIMARY KEY,
value TEXT NOT NULL
);
INSERT INTO season_lookup VALUES(1,'spring');
INSERT INTO season_lookup VALUES(2,'summer');
INSERT INTO season_lookup VALUES(3,'autumn');
INSERT INTO season_lookup VALUES(4,'winter');
CREATE TABLE average_temperature
(
year INTEGER,
temp REAL,
season INT REFERENCES season_lookup(code)
);

Thursday, April 19, 2007

C++学习

发现很多公司要求C++,虽然工作已经有一个了。但7月上班,实在难耐,所以最近想着试几家大一点的公司,看看有没有更好的机会。由于强项在Java,很多大公司都只能望而却步。为了第一份工作一搏!决定重拾C++,发一帖学习日记,一是标出一些重点、难懂的东东;二是记录学习历程;三是可以给google友们多一个找答案的选择。
学习的书是问陈胖子借的,虽然不喜欢中文书,但听说翻译还可以,而且赶时间(就两个月了呀),呵呵,就不计较了。工具是VS2005,-_-b,可能要被小青年鄙视了,因为我整天就唠叨不要用VS,要用GCC。但确实,就业需求所逼,改吧。

Question 1: const
const很复杂,跟指针和引用混在一起更复杂。先两个概念,常量指针和指常量的指针:
int a=0;
const int *p1=&a; //指常量的指针,此处a可以是常量也可以不是,但结果是(*p1)不能再修改
int *const p2=&a; //常量指针,不可以改变p的指向,功能类似引用(但有区别)
const int *const p3=&a; //指常量的常量指针,上面两个特点综合一下

谈到指针和引用,说一下区别,引用是引对象,而指针就是地址。举些例子:
double a=0.0;
const int &b=a; //其实是先 int tmp=a;然后 const int &b=tmp; 因为b要引一个int对象,所以临时创建了一个
const int &c=0; //其实是先 int tmp=0;然后 const int &c=tmp; 同上,先创建一个对象


常量只可以用指常量的指针指。另有书上一例:
int *const &p=a; // 经检验,效果等同 int *const p=a;


Question 2: 陌生关键字
volatile : 表示变量是易变的,Java中也有。但C++中的含义是,编译器不能随意对该变量进行优化处理。即变量在编译器无法察觉的情况下可能改变。
sizeof : sizeof本身并不陌生,只上他有一点比较特殊,,sizeof是编译时刻计算的,因此被看作是常量表达式。


Question 3: 常用STL类型
vector 首当其冲,最好的替代数组的类型。有数组式的使用习惯和STL式的使用习惯,不能随意互用啊:
// 数组习惯
vector<int> vct(10);
for(int i=0 ; i<vct.size() ; ++i)
vct[i]=i;

// STL 习惯
vector<int> vct;
for(int i=0 ; i<10; ++i)
vct.push_back(i);
for(vector<int>::iterator iter=vct.begin() ; iter!=vct.end() ; ++iter)
cout<< *iter << endl;

complex 复数类型,可以用complex<double> 或者 complex<long double>等。
pair 关联两种类型的值。
bitset 向量类型,用 bitset<32>构造向量长度为32。
list,deque,map/multimap, set/multiset
stack 栈,其中与一般栈不同之处是普通栈的 pop删除头并返回头元素,而stl栈只删除不返回,它使用top返回头。
queue和priority_queue,队列和优先队列,priority_queue在Java下满好用的 ^_^。

Question 4: 自己写类
写一个完整的类不容易啊,首先分为三个基本步骤(自己总结的,不知道对不对):
1 类定义,常定义在.h文件中
2 函数、变量定义,.cpp文件的部分
3 添加其他会使用到该类的其他类中的方法,典型的如 istream& operator >>( istream&,类&) 等。

在定义时也能定义部分类函数和变量,在类定义中定义的函数的都是缺省为inline的(使用频率高的,短小的代码可以考虑声明为inline)。在类外定义的需要显示声明inline。

类定义基本结构:

#include <iostream> //包含需要使用的头文件

class Sample; // 先声明一下类

// 声明一些会使用到该类的函数
istream& operator >( istream&, Sample&amp;);

// 类定义
class Sample
{
public:
Sample(); //默认构造函数及其他构造函数
Sample( const Sample&); //拷贝构造函数,如果需要

~Sample(); //析构

Sample& operator = (const Sample&amp;); //重载操作符

void setValue(int); //定义成员函数
private:
int _value; //定义成员变量
};

Question 5: 显式转换
新式(标准C++)强制类型转换: static_cast,dynamic_cast,const_cast,reinterpret_cast
任何非const数据类型的指针都可以被赋值给void* 指针。
const_cast< type >( expression ) 用于转换掉表达式的常量性 (以及volatile对象的volatile性)。
static_cast< type >( expression ) 编译器隐式执行的任何类型转换都可以由它显式完成。
reinterpret_cast< type >( expression) 对于操作数的位模式执行一个比较低层次的重新解释,它的正确性很大程度上依赖于程序员的主动管理。
dynamic_cast<type>( expression )支持运行时刻识别由指针或引用指向的对象。


旧式(标准C++前)强制类型转换:可以替代static_cast、const_cast、reinterpret_cast。

Question 6: 容器
抽象容器类型{
顺序容器(sequence container): list,vector,deque
关联容器(associative container):map,set
}

每个容器支持一组关系操作符,可以用来比较两个容器。第一个不相等元素的比较决定了两个容器的大小关系。
容器的类型有三个限制
  • 元素类型必须支持等于操作符
  • 元素类型必须支持小于操作符
  • 元素类型必须支持一个缺省值
所有预定义数据类型,包括指针,都满足这些限制,C++标准库给出的所有类型也一样。

Question 6: 迭代器
除了iterator类型,还定义了一个const_iterator类型,后者对于遍历const容器是必需的。 iterator算术运算只适用于vector或deque,而不适用于list。

Question 7: 函数
参数为数组,数组确实满麻烦的,首先数组参数绝不会传值,传的是指针。举以下五个例子,前三者相同:

void putValues(int*);
void putValues(int[]);
void putValues(int[ 10 ]);
void putValues(int (&arr)[10]); //参数为10个int的数组,因为参数是引用的,即数组长度成为参数的一部分
void putValues(int matrix[][10], int rowSize); // 第一维长度为rowSize,第二维长度是10
void putValues( vector<int> &vec ); //vector是替代数组的最好类型


指定函数的缺省实参:

int func1(int a,int b=0,int c=0);

int func2(int a,int b,int c=0); // 初始化最右边参数
int func2(int a,int b=0,int c); //可以!此时b c都有缺省参数
int func2(int a,int b=0,int c=0); //错误,bc已经有缺省参数

int func3(int a,int b,int c=func1(1)); //缺省实参可以是任意表达式

int func4(...); // ellipsis 省略号,告知编译器,函数调用时,可以有0或多个实参,而类型未知


命名返回值优化,易犯错误:
1 返回一个指向局部对象的引用。局部对象的生命周期随函数的结束而结束。

Matrix& func()
{
Matrix a;
return a; // 错误,结果将指向一个错误的位置
}



2 函数返回一个左值,对返回值的任何修改都将改变被返回的实际对象。

int& get_val( vector<int> &vi, int ix)
{
return vi[ix];
}

int ai[4] = {0,1,2,3};

vector vec(ai, ai+4);

int main()
{
get_val(vec,0)++;
}


正确使用命名返回值优化:

Matrix& get(Matrix *p)
{
Matrix *res = new Matrix(); //动态分配的,函数结束不会结束
*res=*p;
return *res;
}

函数指针(指向函数的指针类型):

int cmp1(const string &s1, const string &s2)
{
return 1;
}

int cmp2(const string &s1, const string &s2)
{
return 0;
}

int *pf(const string&, const string&amp;amp;amp;amp;amp;amp;); // 错误,返回类型指针
int (*pv)(const string&, const string&amp;amp;amp;amp;amp;amp;) = 0; //初始化,不指向任何东西
int (*pf)(const string&, const string&amp;amp;amp;amp;amp;amp;) = cmp1; //正确,pf 是指向函数的指针
pf=cmp2; //赋值,可以
pf=&cmp1; //可以,同上

cmp1("a","b");
pf("a","b");
(*pf)("a","b"); //三个效果相同,返回1


函数指针的数组(so...神奇):

int func1(const int &a,const int &amp;amp;amp;amp;amp;amp;b);
int func2(const int &a,const int &amp;amp;amp;amp;amp;amp;b);

typedef int (*PFV)(); //定义函数类型指针的typedef
PFV tc1[10]; // 函数指针数组长度为10
PFV tc2 = { func1, func2 }; // 初始化
tc1[0] = &func1; // 赋值
tc1[0](10,20); //调用
((*tc1)[0])(10,20); // 显式调用


函数指针可以作为返回类型,但是函数不能做为返回类型:

int (*func(int))(int, int); // ff为函数,有一个int参数,返回一个指向函数的指针,该指针类型为 int (*)(int, int);

typedef int (*PF)(int, int);
PF ff( int ); //更优雅

typedef int func(int, int);
func ff(int); // 错误,返回类型不能是函数类型



Question 8: extern
链接指示符 extern "C" / extern "Ada" / extern "FORTRAN"
告诉编译器,该函数是使用其他语言编写的:

extern "C" void exit(int);

extern "C"
{
int printf( const char* ...);
int scanf(const char* ...);
}

extern "C"
{
#include <cmath>
}

Question 9: 头文件
头文件为所有extern对象声明、函数声明以及inline函数定义提供了一个集中的位置。
预编译头文件而不是普通头文件可以大大降低应用程序的编译时间。
头文件不应该含有非inline函数或对象的定义。否则将可能使同一程序的两个或多个文件中包含,就会产生重复定义的编译错误。


Question 10: 域和生命期
局部对象:自动对象、寄存器对象、局部静态对象

自动对象地址不应该被用作函数的返回值,因为函数一旦结束了,该地址就指向一个无效的存储区。当一个自动变量的地址被存储在一个生命周期长于它的指针时,该指针被称为空悬指针(dangling pointer)。

寄存器自动对象:在函数中频繁被使用的自动变量可以用register声明。

for( register int ix=0; ix


静态局部对象:未初始化的静态局部对象会被程序自动初始化为0,相反,自动对象的值是任意的,除非它被显式初始化。

动态分配的对象:空闲存储区被耗尽时,new表达式失败,所以抛出一个bad_alloc异常。delete会调用操作符delete(), C++保证若指针被设置为0,则不会调用delete(),故之前没必要测试指针是否为0。但delete之后,并不会把指针赋值为0。

auto_ptr
auto_ptr可以帮助程序员自动管理用new表达式动态分配的单个对象,不支持数组。


#include
auto_ptr< type_pointed_to > identifier( ptr_allocated_bynew );
auto_ptr< type_pointed_to > identifier( auto_ptr_of_same_type );
auto_ptr< type_pointed_to > identifier;

auto_ptr< int > pi(new int(1024));

由于操作支持都是内联的,所以效率不比直接使用指针代价高。ptr相关操作:
reset: 初始化后,就只能用reset再对auto_ptr赋值了。
get: 返回auto_ptr对象内部的底层指针。
release:允许将一个auto_ptr对象的底层对象初始化或赋值给第二个对象,而不会使两个auto_ptr对象同时拥有同一对象的所有权。

定位new表达式:

new ( place_address ) type-specifier // 表达式格式

class Foo{};
char *buf = new char [ 1024 ];
Foo *pb = new ( buf ) Foo; //无须delete
delete[] buf;

韩片《无道里》

最近看了几部电影:《忍者神龟》(美)、《汉江怪物》(韩)、《博物馆之夜》(美)、《无道里》(韩)。发觉韩片真的相当地出色,拍摄手法啊这些专业的东西我是不清楚,但是剧情确实相当有看头的。《无道里》我是今天看的,虽然是喜剧,但却折射出了一些内心的东西。最后,剧情的巧妙给了我一个意外地冲击,流了两滴泪。



这里是“无道里”,除非你想跳崖,不然不会到这里来。一日,在悬崖边的小村庄里居住的三个老头发现悬崖边上留着一双鞋。不久,跳崖者的家属来到了小村庄,当老头把鞋递给跳崖者家属的时候,家属留了笔钱给三老头以表示感谢。于是,一边是跳崖(自杀)胜地的扬名,另一边是老头们商量着如何靠跳崖发财。
再看首尔,一名女记者因为找不到够爆的新闻,正在发愁的时候,在一家网吧意外发现了一名准自杀者留下的〈自杀者天堂〉网页。女记者意识到发财的机会来了!于是出动吧。

大家齐聚“无道里”,晚上开开自杀讨论会,第二天早上去自杀,未遂,晚上再开会,早上再自杀,未遂...... 老头们也在想尽办法催大家赶快自杀...... 你急我也急...... 最后...... 想知道最后怎么着了?自己看电影吧。(注意海报最左边的老头~ 很色的哦 ^_^)

Install Jetspeed with PostgreSQL

Since my graduation design request PostgreSQL, I have to give up MySql. PostgreSQL is quit different from MySql, as most extension commands of MySql, like SHOW TABLES , does not work in Postgre, and the structure of Postgre is entirely unfamiliar for me.

Although the installation of Jetspeed's DB is so simple that just three steps:
1 create a database
2 grant the privilege
3 download the JDBC
which still took me almost two hours to accomplish it, for the account and network configuration is some bit complex.

First of all, write a test java file, which is of great help, the following code (replace 'testdb') should be included in the file:
Class.forName("org.postgresql.Driver");
Connection db = DriverManager.getConnection("jdbc:postgresql://localhost:5432/jetspeed", "jetspeed", "jetspeed");

Compile it, JDBC file was not necessary during compilation phase, but it should be appended to the classpath before executing the test program.

Second, install PostgreSQL if it was not installed before. Source installation would be a better choice, and here is the link of PostgreSQL official site. Install via apt would be the most convenient way, I like apt and ubuntu :) .

Third, initialize a DB cluster(apt installation has already initialize one), like the following command:
$ initdb -D /usr/local/pgsql/data

Find pg_hba.conf and postgresql.conf in the directory of DB cluster. Login the cli environment of PostgreSQL (notice: there are two databases already exist, template0 and template1):
$ postmaster -S -D /usr/local/pgsql/data  #start the db server background
$ psql template0


Fourth, assure that the TCP/IP connection was available. Modify postgresql.conf as below:
listen_addresses='*'
port=5432
tcpip_socket=true


Fifth, modify pg_hba.conf (refer to this):
local all    password
host all all 127.0.0.1/32 password

Caution: Start a new line at the end of file. And restart the server after the configuration completed.

Sixth, create a user and create the database, then grant the control privilege to the user. There're several ways to do it, just like this one:
$ createuser -d -P  # create a user with the privilege of database create and a prompt for the password of the new userd
... # input the user info,like username is 'jetspeed' and password is 'jetspeed'
$ createdb jetspeed -U jetspeed -W # create a new db and the creator is 'jetspeed'
# if error reported, maybe pg_hba.conf was incorrected configured.


Seventh, run the JDBC test. If the test succeed, there would be no problem of Jetspeed installation.

Saturday, April 14, 2007

2007年4月的第二周

这一周很忙,也很闲。
首先是上周五,毕业设计需要我去合作的那家单位走一趟。早早地我就起床了,按着昨日网上找好的路线找了2个半小时左右,后来与老师电话后才知道,我找错单位了 -_-b 。随后老师让我不用去了,他们谈好了再通知我。心中一边抱怨着这个不知道在瞎忙什么的毕业设计,一边
低着头沮丧得走着那2小时的回家路。

周一、周二,我奉献给了学校,也就是我那毕业设计。因为了是签了合同的项目,老师又希望我冲优,所以我一直也不敢怠慢。但是,那个单位不懂装懂的一套莫名的号称“创新”的设计实在是把我惹得对该项目厌恶之极。两天的下午,我就坐在那里(傻傻地),装着一些我认为几乎没有价值的,至少对我的毕设而言是没价值的,却又是相当复杂的系统(globus toolkit)。而我要做的那部分(portal),已经完全被搁置了,写完前端后一直等那个单位给我接口,但最后等到的,除了“下周给”还是“下周给”。不是说他们不干事,真的,为什么这么一家还算不错的公司竟然效率这么低呢。

周三,topcoder的marathon结束了。由于浪费了太多时间在毕设上,周三想恶补一下tc的,但最后还是没能如愿,反而最后一次提交的成绩还不如之前的那次好。说实话,这次的marathon是很有趣的,我真的满想静下心来认真做一下。但是除了毕设,周四还有一个相当重要的面试。

周三早5点,我起床,为了周四不知道,周三先去摸摸情况。2小时的路程将我整得相当疲惫,又是2小时的回程,回到家里人像一滩泥,散在椅子上了。不过我硬撑着,如果现在睡了,那么晚上我一定睡不着,所以为了明天早起,不能睡!

周四早5点,起床,准备就绪,出门。今天有个大面试,之所以如此重视它,除了公司名气相当大之外,还有两个原因: 一是已经有我的两个好伙伴收到了公司offer(就是他们推荐我的),为了我们能一起在这家公司里闯事业,我很希望能够进这家公司;二是该公司的面试十分专业,除了让我感受到了公司招人的诚心之外,公司的办事效率也相当值得称赞。面试要持续到下午,做了10道左右的题目,其中写了完整程序的有5道好像。有一道卡住一会,但在面试官的提醒下还是说出了解题的关键算法。还有一道与面试官在题意上有冲突,虽然一开始和面试官有点交流不畅,但后面的两个问题还是解决得满顺的。第二面十分完美,除了题目在很短的时间内做出来以外,中间发生了一段小插曲:我的肚子叫了(-_-b 早饭没吃饱啊),面试官很友善地给我拿了咖啡和饼干,咖啡很好喝。另外,最后一位面试官送我走之前,给了我一个KFC汉堡包,^_^,对公司好感度顿时增加到100%!总体感觉还是不错的,事后我有发觉我的程序还是有漏洞的,但我想结果并不重要,我把我解决问题的思路和方法展现给了面试官,所以面试还是成功的。

面试结束后,我去超市买了不少吃的,脑力和体力消耗太多,需要补一下。晚7点,做tc算法的round 1c,虽然人还是有点疲倦,但听说过round 1就有飞盘~,拼了!第一题很容易就解决了。第二题卡了,写了个DP,但结果始终不对。想到了二分答案,但是我不会写二分答案的算法(知道有点像二分搜索,但因为从来没写过,一下子也摸不着头脑)。结果只做了第一题,最后的结果是排名152名好像。晋级是没有问题的,只是只做了一题,始终感觉不是很爽。过两天就是round 2,+U。

今天marathon成绩出来了,排名150+,不理想,rating也跌了不少。另一件关于tc的事是我的blog增加了一个看tc算法赛事的widget。原本我用flash写的一个,有图片,类tc个人资料的那个flash的。但后来发觉导出成swf就怎么都连不上topcoder,那就拿不到feed了,但是exe和直接在flash IDE下调试是完全成功的。郁闷,不能出swf那就不能挂在blog上了,所以花了半天时间再写了一个javascript的,只是是文字,跟图表的效果是没法比的。



附加一个用CSS 做 tooltip的好文章链接:
http://www.communitymx.com/content/article.cfm?cid=4E2C0&print=true#

为什么我一开始说很忙又很闲呢,忙得是这周事情不少,闲的是大部分事情都只是在花时间和体力,比如毕设、flash的tc rating表白做了和面试那两天的8个小时路程,总有一种在浪费时间的感觉。

Saturday, April 07, 2007

Cute Otters.

Otters hand by hand, looks so sweet.

I saw them on the news and decide to check it out, they're stars now!

Tuesday, April 03, 2007

TCO Marathon Online Round #2

TCO Marathon OR2 finished. I got 65/445 rank, 11331.73 score, and advance to round 3 successfully. My friend, FinalLaugh, got rank 191, while he has got 200 rank when the submission parse finished, just by a finger's breadth. The path to Las Vegas is becoming more and more narrow, next time , we will fight for 50 contestants position.

The top 2 players' program scares me a lot...... So many codes that looks like "AA>s;oI2A". As we, FinalLaugh and I, discussed, it's a technology of compress.

I dislike this problem, two reasons: 1st, it's a gambling game; 2nd, it's solution is not so hard, but with a lot of work. My solution is so easy to implement , somewhat like saarixx (rank 7) did.

First of all, list all card combinations: {4,4} {3,3} ... 15 cases from high to low. Then, provide a simple solution to newcard(), round1(), draw() then take them into an array, each owns 15 elements, just like this:


 private int[] newc = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0 };
private int[] rd1 = { 2, 2, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0 };
private int[] draw = { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2 };



For these three method, I think, a fixed strategy will be ok. As to round2(), it's more complexity, but as I'm so lazy.... I realize it like this:


   public int round2(int card1, int card2, int bets1, int bets2, int drew) {
int idx = getCardIdx(card1, card2);

// pre solution, like the too little card will return 0 immediately

switch (drew) {
case 2:
// some solution
case 1:
// some solution
case 0:
// some solution
}
return -1;
}



That's all, so simple but strong enough to advance to the next round. Wish my good luck next round!

Friday, March 30, 2007

TCO Marathon Online Round #1

TCO Marathon OR1 and OR2 has finished today, which consume my thoughts for two weeks.

To OR1, I got 1309.01 at submission phase and 4990.66 at end, final rank 67/532. See the problem here(need login), which is a really interesting and challenge game. As my solution, the image could be considered as a onion, the target of this prob is to peel the onionskin. So, here is the steps of my algorithm:

1. Generate the rays, those rays will be the easy calculating ones. (Attention, generate rays does not mean call the measure() method.)
2. Pick out the rays that just cross one unit('x' unit), and store them in a queue.
3 Iterate the selected rays, calculate the density of that unit(call measure() here), and then mark the unit as calculated.
4 Repeat step 2, but the more repetition we used, the more precision we will lost. It should be a bound to control the precision before we start this algorithm.

As to step one, the rays should be selected meet the condition that they will be easy to calculate, otherwise, it will be a great amount work of calculation and simulation. As I considered, each ray will start from one of the four corners of the unit, and the ray should cross exactly n row unit while it crossed 1 col unit, and vice versa. The main reason I ensure this condition is that every length of the row unit( according to my example) that the ray would cross is the same, and that would lower the complexity of the ray calculation. As a result, when n is greater than 30(I forget the exactly number, but 30 is enough), every unit will be covered.

As to step four, the repetition times is a hard decision. The performs of different repetition times would result in a normal distribution, and the peak of the distribution is the one we desired. I choose the repetition according to a great amount of test.

Wednesday, March 14, 2007

《大唐西游记》 [探索·发现]

记录片《大唐西游记》,制作在国内算是十分精良的了。全力推荐!

音效出众!配音出色!
对《西游记》名著的动画表现,充满了活力!
而对历史的重现采用虚拟3D技术,虽然技术上还有不是十分完善。但足以用来描述好这段神奇的冒险故事了。

推荐!强力推荐!
喜欢记录片的朋友千万不要错过了!

Wednesday, March 07, 2007

解决系统盘空间不足

我的系统盘只有4G。虽然平时我已经很注意保持系统盘的清爽,但还是总免不了“磁盘空间不足”的麻烦。满惹人的,于是在网上搜搜有没有达人能给我一点好的idea。没想到确有高手,以下是该文的引用:


其中第7、8条真是杀手锏!把100M不到的空间释放到1G多,汗颜,原来有这么多垃圾没清理掉。
第9-12条是清除平时不用的windows文件的,有一点危险性,不过知道东东的含义就不怕啦。

13、14和27的bcd都是值得推荐的方法,算是比较温和的方法却能很大程度上改观当前系统盘的尴尬局面。

Thursday, March 01, 2007

Widget for Google Calendar

See my blog's left bar, there is a fantastic widget that shows my google calendars in the form of event list and calendar table.

Now, the widget is available here:
http://ray58750034.googlepages.com/googlecalendarwidget

Reply your comments, ideas and the bugs you find about the widget here, thx.

Friday, February 23, 2007

Graphics program with Javascript

Apple introduced a new HTML tag <canvas> to the world, which endue client-side script language the ability of graphics drawing. Now, Firefox and Opera has implement the <canvas> tag, so the javascript programmer was able to write a rich graphic-based client application.

I've written a simple ball game to show the interactive between javascript graphic app and browser user.

See details : http://ray58750034.googlepages.com/javascriptballgame
See more examples : http://developer.mozilla.org/en/docs/Category:Canvas_examples

Wednesday, February 21, 2007

Topcoder SRM340 DIV II

首先叹一下只能沦落在Div2和Div1的边缘。颇为伤感,以后想做Component了。

多么戏剧性的一场比赛啊,第一题还是很稳健的敲掉了,毕竟DIV2第一题太没搞头了。第二题其实也很简单,但比赛的时候,人就容易犯糊涂。 我把第二题先想成dfs,写完后发觉超时,郁闷。然后越想越复杂,想到了DP,DP的路就越走越远拉。最后是235.85收场。

第二题,其实枚举和贪心就行,巨汗呐。不过在Challenge阶段,表现神勇啊!一路从18冲进前10。主要是靠事前准备的对付第二题dfs的数据,哈哈,果然有用dfs还不知情的,连掐3个 ,HOHO。当时排名第10, score 385.85。

最后的System Test是关键!第三题全军覆没,房间里没人过。第二题就第一个人过了。然后,因为我掐了三个人,所以我的总积分排第二!巨汗啊,居然排到了No2,不枉我通宵比赛,呵呵。总结一下,第二题我其实TEST数据早过了,但由于我确定我的程序不完美,所以我一直不交。看来战术是正确的!如果交了被掐掉,那就很尴尬了。

按规则,这场比赛有奖金可以拿,多少无所谓,只要确实有拿就好。拿到钱得请梁大吃饭!梁大应该是说比我做的好,但是最后也是只有一题过了,再加上没掐,所以分数比我差。当然他们房间的整体实力可能还比我这强一点。

Saturday, February 17, 2007

HSB Color Space

java.awt.Color类有根据HSB色彩空间创建Color的静态方法,今天去查了查。了解了HSB是怎么一个色彩空间,它和RGB又有什么区别,分享一下。

下图的圆锥描述的就是HSB如何表示色彩,相当华丽吧:

Hue:描述色彩,其值为 [0,360) ,是圆锥顶部的圆,其0和360均为红色。另外60为黄、120为绿、180为青、240为兰、300为紫。颜色如彩虹~呵呵。

Saturation:描述饱和度,其值为[0,1]之间的小数,图中是圆锥的轴到圆锥的边缘。取0则是纯白,无论Hue取多少。

Brightness:描述明亮度,其值为[0,1]之间的小数,图中可以说是圆锥的高度,自底向上逐渐明亮。当取0时,色彩为纯黑,无论Hue和Saturation取何值。

参考:
http://www.tomjewett.com/colors/

IE 好龊

微软自家的东西都兼容这么差,IE居然不如Firefox识别能力强。 -_-b

Friday, February 16, 2007

Javascript Menu 代码

只为了显现一个简单的menu,网上搜了不少代码。 但要么就是太复杂,搞得我改都无从改,要么就是不符合我的需求。结果自己静下心 20分钟就搞定了, -_-b ,找了大概2小时啊,汗呐。

非常简单的要求:
  1. 必须是js代码,因为我要实现menu在很多页面里都要用,如果掺了html就要用iframe之类的,iframe毕竟不舒服啊。
  2. 对界面没什么要求,简单的ul和li就行了,css沿用站点的,无须另外配。
  3. 多级目录结构
  4. 每层menu可以是链接,也可以是打开子目录
  5. 可复用,其实就是实现类似jsp的<%@include file="">的作用,只是我没有服务器,所以只好用js啦。
先看效果:



以下是我的代码:

<div id="soya_menus">
</div>
<script language="JavaScript">

var MENU_ITEMS = [
['Ray',{ href : 'http://raythking.blogspot.com/',target : "_blank" }],
['Google',null,[
['Web',{ href : 'http://www.google.com',target : "_blank"}],
['Image',{ href : 'http://images.google.com',target : "_blank"}],
['Video',{ href : 'http://video.google.com',target : "_blank"}]
]
],
['Baidu', null,[
['Index',{ href : 'http://www.baidu.com/',target : "_blank"}],
['Zhidao',{ href : 'http://zhidao.baidu.com/',target : "_blank"}]
]
],
['Sogou',{ href : 'http://www.sogou.com/',target : "_blank"}],
['About',{ href : 'javascript:alert(" This is a simple javascript menu !")',target : "_self"}]
];


function showSubMenu( tolist ){
var sublist = document.getElementById(tolist);

if(sublist.style.display == ""){
sublist.style.display = "none";
}else{
sublist.style.display = "";
}
}

function insertMenu(divarea){
document.getElementById(divarea).innerHTML=createMenu(MENU_ITEMS,"soya_menu");
showSubMenu("soya_menu");
}

function createMenu(menu_it,id_pre){
var html="<ul id='"+id_pre+"' style='display:none;padding-top:8px' >";
for( var i=0 ; i<menu_it.length; ++i){
var sub_id_pre=id_pre+"m"+i;
html += "<li>";
if(menu_it[i][1]){
html += "<a href='"+menu_it[i][1]+"'>";
html += menu_it[i][0];
html += "</a>";
}else if(menu_it[i][2]){
html += "<a href='"+menu_it[i][1].href+"' target='"+menu_it[i][1].target+"'>";
html += menu_it[i][0];
html += "</a>";
html += createMenu(menu_it[i][2],sub_id_pre);
}else{
html += menu_it[i][0];
}

html += "</li>";
}
html +="</ul>";

return html;
}

insertMenu("soya_menus");

</script>

Wednesday, February 14, 2007

不同浏览器下装载js的不同表现

这两天在改blog,因为脑子里又掺了一些杂七杂八的念头,想要实现一下,呵呵。如果这两天有看我blog的话,可能时不时会发觉自动跳框啊或者某个功能怎么没了等等状况。那就是我在改blog,这个时候要找我的话,直接上gtalk就行啦。

为了实现多个浏览器下效果一致,花了不少心血啊。先看看效果吧,见左边的“日程更新”,我的Calendar是以event list形式表示,当然可以有其他选择,这是后话(有空时候再说吧)如果是Firefox的话可以看到边是带弧的,是用的css3,ie和opera下没看出来。ie下还有其他一些css效果也看不出来。不过基本的效果是三个都一样的。

因为涉及要下多个Calendar然后合并的操作,发觉三个浏览器对于js下载和加载的表现各不相同。在做Web可要特别注意了哦,在这我说一下我遇到的情况吧:

情况如下,首先要下载四个Calendar的数据(用Google 的 JSON API),每个下载完回调一个Handle,Handle将数据加入EventList。四个都Handle过了,调用showEventList()。三个浏览器的下载方式应该都是并发的,这点应该没有疑问。每一个Calendar的操作相当于是在一句<script src="****"></script>,加载顺序正好三种浏览器三种方式。


首先是IE,由于对多个Calendar操作,然后用到了一个eventlist,可以想象是多线程在操作一个数据域。IE可以说是完全多线程的,如果给Calendar编号 1 2 3 4,那么在下载完数据后回调的顺序可能是 2 3 1 4 或者 1 3 4 2 等等。另外,用来动态加载这些javascript的那段js与这四个新js也是并发的。这样有两点麻烦:
  1. 时间上难掌握:程序是非顺序的,对于需要顺序完成的任务实现时要加不少辅助变量。
  2. 空间上易出错:由于好几个Calendar的Handle是同一个Handle,这样就要手动控制好变量的同步,容易出现脏数据。

然后是Opera,Opera不论从哪方面讲都适合年轻人使用,充满了朝气!今天的修改其实主要是针对IE的,Firefox和Opera基本上是一致的。但在最后,Opera的一个反常举动让我调了老半天才调出来。
Opera的js装载好象是完全顺序,与IE截然相反。顺序到一个页面的所有script都得一步一步来,就像只有一个线程。如果以原script为 0,四个数据js文件还是 1 2 3 4,那么Opera的执行顺序将是 0 1 2 3 4 0,最后的0是返回原脚本,感觉就是堆栈式的函数调用。就是最后那个返回原脚本,让我措手不及。楞了老半天才发觉。


最后是Firefox,个人觉得,Firefox 更适合用来开发 web 程序。就在今天的修改过程中,无论我怎么改,只要基本的逻辑是对的,那么Firefox的效果始终是如预期的。
以Opera那种假设下来说,Firefox的执行顺序是 0 1 2 3 4。我觉得这样理解好了,Firefox是把script放在页面文件中。装载顺序是从头到尾依次装载的(严格按照js在页面中出现的顺序),js的运行不并发,装一个运行一个结束后再装。几个好处吧:
  1. 更贴近web开发者的正常逻辑。web开发者一般是写页面的时候嵌js,而不是写js的时候嵌页面 。这样Firefox显然比Opera更适合web开发者。
  2. 脚本并行处理(IE)考虑了一块js一个用途的方式时候的效率,但是不适合多个js联合工作,特别是需要时间上和空间上控制的工作。

其实单就用户体验来说,IE可能更受欢迎,毕竟是多线程的,不会因为一个js的错误而导致整个页面僵死。而且就三个浏览器看我blog的速度来说,IE应该是比较快的(除了Opera在有缓存的情况,其缓存给我的印象颇深刻~)。但我还是比较喜欢Firefox,毕竟咱是做“写”工作的人嘛,而且速度这个是可以用不同手段提高的。

最后赞一下Firebug,开发人员的福音啊!

Monday, February 12, 2007

GNU主页,无语了

看了GNU的主页,无语了。



Orz Orz Orz
Orz Orz Orz




http://badvista.fsf.org/
网站 logo ,太牛了,汗呐。


其实学得越多,就越是看到微软的黑手扼杀了多少开放、有活力、有想法的人才和思想。某种程度上,我是满崇拜Gates的,但有时候看到微软做的事情实在是不得不让人发横。
用了这么久了,也该换了~。

Saturday, February 10, 2007

API地图应用大赛

51地图举办的地图API比赛,API确实好用!赞一下51地图。
主要是看中了参与奖是一年的免费《程序员》,不过比赛要五月结束,准确地是说是半年多的《程序员》 -_-b 。

从吃完晚饭到现在,简单地实现了一个idea,先暂时搁在blog上。idea是从新闻里看到现在维修服务(包括小区物业、也包括马路边的公共设施等)讨论得特别多,什么水龙头漏水、空调坏啦、还有道路不方便等等都要报修,好的十几分钟就到,差的搁了几个月也没人管。

所以,我想是不是可以利用地图来做一个“我要修”(不是我要秀)的网站。服务流程如下:
  1. 客户端提供报修,报修人必须提供身份认证,不能让我们的维修工人白忙活,要保证可信度。(认证方法可以替换掉我的sample的身份确认那个输入框,可以用手机号码做为输入)
  2. 身份认证后,报修人标明地点、填写报修详细。标明,可以是输入地点自动标明(比如输入东方明珠,地图可以自动标到东方明珠),也可以手动标记(手动标记就不显示地点名了,改成坐标)。
  3. 确认填写信息无误,发送给服务器端。
  4. 报修中心可以固定时间来看报修情况(比如在人员有充沛的时候),然后选择距离该中心近的点派职工去维修。
  5. 对于报修成功的用户给以虚拟奖励......这是后话。
我这粗略地实现了客户端的地图(当然是用51的API啦),后台是没有服务器端的,毕竟我这只是blog嘛:


自动标记地点

(请输入证件号以便身份确认)



打开城市地图 打开手动标记 提交报修申请




Friday, February 09, 2007

看《落叶归根》后感

说实话,很值得一看,很值得深思的电影。

看过《十面埋伏》、《英雄》、《无极》、《夜宴》,这都什么呀,除了大把大把的丢钱,道具买最贵的,地点找最好的(爽一下,然后留个烂滩),然后讲的都是一些不伦不类的、神经质的、莫名其妙的。最近的《满城尽带黄金甲》可谓是此类影片的颠峰,在帝皇身上乱伦、钱花得看着就心疼。最后一段父亲抽儿子尸体那一段,我气得真想上去抽发哥。不谈也罢,看完之后一点都不想再碰这东西。我说拍艺术么关着门自己看你的艺术不就好了吗,我就一coder有闲的时候才去看看最近宣传什么大片(其实我就看过几部宣传力度比较大的影片),管他艺术不艺术、能让人看了喜欢就好,却看到这么恶心的东西,气死,活活气死。但李连杰在《黄金甲》首映式上的慈善宣传另当别论(艺人,就是要告诉大家什么是好的)。

《落叶归根》的故事就是这么一个感人的故事(明星很多,都是很讨人喜欢的明星),我也是先知道了故事再去看的电影。对原故事里加了许多,特别加了不同的人和不同的事。草草的开头、草草的结尾,故事本身已经很感人的,开头和结尾没什么必要多谈(其实头和结尾就这么回事,能拍什么脚指头也想得出,不拍反而到觉着干净),省下更多的时间给更多的故事。公路电影,就是一边走一边拍,电影的分类就决定了遇到很多人很多事儿。影片中冷漠的人群是一个频繁出现的主题,有时甚至将主角逼到了死胡同,这是社会普遍存在的现象,不好多说什么,因为中国本来人就多、又杂、而且无信仰者居多。所以有那么点现象理论上是成立的,只是叫人心理不舒服。

影片的亮点是好人,并不是所有的好人都是好人。影片开头的劫匪就不是好人,但仗义,坏人或多或少应该有那么一种品格,这样就算是坏但也算是个人了。给自己办葬礼的老头,没有什么特别出挑的看头,不过就是农村人的朴素和真诚,无形之中给人亲切的感觉(让我想起了爷爷和他的老家人,其实本土的上海人基本上都是是乡下人的后代)。去西藏的青年,体现是新青年豁达开朗、乐于助人的一面。轮子,可以说是一个喜剧的片段,导演似乎要告诉人们,人虽然生活在底层,但一样有思想、一样有生活情趣。养蜂人,讲爱情,养蜂人孩子的诗歌,讲爱国情,理发店的打工妹,讲思乡情,和捡破烂的之间的黄昏情,都是一些至真至切的感情。还有双簧,可以说是高潮,之后捡破烂的儿子的故事,让人心酸,也不说什么了,好好爱父母吧。影片中警察的形象一直是公正、正义的。不是说什么拍谁马屁,有两点:其一,现在社会上执法人员丑陋的事情批得太多了(说明某种程度社会进步了),但思考问题不应当片面,只有把好的形象立出来,丑陋的地方才有机会改过来;其二,我想影片主要的收看对象是工农阶级的,如果把执法人员的形象再坏掉,那他们心中的未来、理想何去何从?影片有个小细节,车上的孩子给老赵递了瓶水,是和其他人的一个反差,人性还是善良一点的好呀。

最后要赞一下的沿路的美景,公路电影的一个重要的因素!赞一下祖国山水。比《黄金甲》里那种景色要美得多了,而且不容易产生视觉疲劳等不良影响。

最后搜了一下电影网上的反映,好象票房已经紧逼《黄金甲》了,好评如潮。另外国外应该也有市场,除了主题适合各地华人,毕竟这也是一部真材实料的电影。

Thursday, February 08, 2007

Topcoder Marathon 11

Marathon的System Test也是Marathon式的,等了好久。


最后的Rank终于出来了,Rank 8, Score 388.10, Rating 1565。
第一名好夸张,有好多Case都是超我一倍的呀!赞~


第一次做Marathon,这次的题目是贪吃蛇,郁闷...是比较没新意的题目...个人感觉贪吃蛇运气因素较大(测试数据多的话,当然可以降低偶然性),没有觉得能在每盘上都赢得最高分的算法,但确实应该有能保证在大多数情况下表现出色的算法。
我的算法可以说是偶然性十足 -_-b,我也很纳闷,但就是没法解释,所以只能说偶然。Example Test 15次,Submittion 4次, Submittion的成绩是 30.76 -> 28.44 -> 28.13 -> 27.43 一个比一个差 -_-b (但我的想法好象是一个比一个周密才对呀)。

我的算法的思路是这样的:

Step 1. 将Snake的一次行为(调用 moveSnake())划分为三个小算法, 即计算路径、选路径、移动。

Step 2. 初始化地图我不算在算法里,因为太简单了。计算路径是指,用搜索类的算法,搜索出从Snake到Food的可能路径。

在这一步,我起初使用的是最简单的bfs(就是我得分最高的时候 -_-b)。优点是找到的豆路径最短,缺点是Snake老是擦豆而过,因为路径只关心最短的问题,如果路径上没有经过某个豆,那么即使该豆可以顺便吃掉,Snake也会置之不理。
然后,我改进了算法,使用pfs,以吃到的豆的个数为优先级别进行路径搜索。这样每次都是从吃豆最多的路径继续往下搜,就可以保证将顺路的豆子都能吃掉。结果是,这个pfs每次比bfs走的步数要少,从虚拟程序上看,Snake聪明了许多,但就是吃豆数不见长。

我这有一个我没去实现的算法(因为后面两天都有事),想法是使用多端bfs:Snake头和各个Food各准备一个队列,然后每个循环,依次对每个队列进行扩展。当某个Food队列扩展的路径碰到了Snake的路径,那么Snake到该Food有路;若是Food队列碰到Food队列,那么这两个Food有路。且所有路径最短。改算法的好处是能求出所有最短路径、而复杂度与bfs相同,只是实现有点复杂。

Step 3.选路径,在我自己测试的时候发觉,选路径对于整体结果影响最大!也可以说是偶然性最大的一块。依据Step2中的bfs或者pfs所得到的结果,应该说Snake到Food的路径是固定的,所以就可以说是选下一个受吃的Food。怎么选Food呢?
我给每个Food设置了三个值:
  1. 吃到该Food的路径上顺便可以吃到的Food
  2. 假设Snake吃该Food,那么吃到Food后,Snake的可移动空间,即一次bfs从Food点开始计算空间(要先模拟好Snake吃到Food的位置)。
  3. 该区域内还有多少未吃的Food,即如果Snake逃不出该Area,可能还有多少Food可以吃。
综合上述三点,可以计算出一个优先级。我以Area大小和Snake蛇身长度为主要依据,若蛇身长远远超过Area那么Snake应该说可以有更大的活动,也可以说Snake有机会逃出该Area。再依据Snake吃该Food时顺便吃的Food和该Area潜在的Food同样影响这个优先度。若优先度相似,则可能再吃的Food数量加上顺便吃的Food数量为第二优先级。
在这里,Area的关系十分重要,很明显的,因为Area表示Snake存活概率高,只要活着就不怕没Food吃。
比如下面两个情况:

# ###
#O # #
# #O#

很明显,这些Food是DeathFood,优先级要最低,也就是说实在没Food可吃才吃他们。

对于多端bfs,选择的就不是Food了,而是真正的Path。这个就可能和前面的算法完全不同了,我又没实现多端bfs,而且这个貌似更加复杂,就没深入。。。另一方面是被偶然性搞怕了,深怕花了大半天写的程序结果还不如以前的好。

Step 4.移动,即与平台交互,这个只要认真看看平台文档就行了。另外,为了保持Snake和Food位置与平台同步,自己也要模拟Snake的移动。

附加一个想法,由于Step3提到,Snake吃到Food后的Area问题。所以我考虑是否可以通过预广搜一次,标记所有的Area(或者这里称Prison,也就是整个Area有一个格子负责与外界连着,其他格子均与非此Area的格子无连接)。起算法是,由任意一点,开始bfs,但搜索到的格子只有一个目(类似于围棋的目,就是下面这种情况,X是搜索过的格子,#是障碍物,@就是只有一个目):

XX#
XX@
XX#

这种情况下,将@放入一个Door队列(初始为空)。若搜索第二次遇到@,则@不是Door,标记为搜索过的格子。在待搜索队列为空时,若Door个数大于1,则Area不是Prison,可以再扩展;否则该Area为Prison,同时去除该Door。然后任取一个外面一个没有搜索过的格子再bfs,同样,若搜索到某个Door则取消它Door的资格,否则搜索完再计算Door个数。
可能出现这种情况: Prison - Door - 2个Door的Area - Door ,此时,2个Door的Area不是Prison,但它加上里面的Door和Prison就是一个Prison。可以说是有层次关系的。
总之,算法很复杂,当时摆着电脑楞了许久,最后还是决定先暂时把这个想法搁着 -_-b 。

Sunday, February 04, 2007

07年2月3日

昨天发生了好多事情,实在不得不记录一下。
早晨9点多,手机铃声把我吵醒了,是我母亲打电话过来叫我快点整理东西,他们马上就到,要接我回家了。回家,家离学校不是很远,但第一次感到这么温馨啊,这次是真正的回家了,要开始准备工作、面对家人、步入社会了。

11点多回到家,首先要把小房间整理一下,乱七八糟的东西实在太多了。已经有三年没有怎么动过小房间了,理出了不少回忆。虽然在进大学之前很贪玩,许多回忆之后都让我颇感悔意,但毕竟这是我的历史,不能像日本人那样,咱该承认的就得承认,以下是罪证:

第一张是追星历史,当时特喜欢欧美的组合和歌手,一有他们的新闻就剪下来 -_-b ,最大的那张美女照是至今都满红的小甜甜Britney,收集了最多的是Backstreet Boys的,还有N' sync、Moffatt和HANSON家庭组合,现在把这些剪报都整理在一张小信封里,准备丢了,回想起来当时确实满幼稚的。除了剪报(其实是很小一部分,小得我发现他们的时候都有点惊讶),CD(正版哦,花了不少父母的血汗啊,悔过ing)和海报(基本也撕光了)才是最多的。CD要留着,老价钱的呀,或许将来可以卖个好价钱(嘿嘿)。
第二张是游戏历史,游戏好比毒品...深有体会,高中一直沉迷游戏,单机游戏玩过一点(和游戏大老leaderz比起来实在很少),而毒我的要属网络游戏,而毒得最深的莫过于《石器时代》和《魔力宝贝》了。图片上的红龙盒子是《石器时代》当时榨取人民财富的罪证,当时这样的包还是限量的,我特别预定才买到,记得那时候这东西炒得很热,黑市上200一个都有。结果等热潮过了之后才发现,原来到处都有买,根本不是限量版。而盒子里的东西很少,就是安装必须的东西,再加一个充气玩具,其主打的是虚拟商品,就是包里的抽奖号码可以中一个游戏中的宠物。地上的点卡30元一张啊,照片里应该是1/5都不到的一部分,而我所有的点卡还不到我另一个好朋友的1/5,对不起父母啊 :( 。
最后的一张是小时侯很喜欢玩的四驱车,益智的,满不错,就是要让车子跑得快、跑得稳还是得花钱...

整理完了一大堆的历史遗留问题后,我去邮局把SCJP的证书拿了出来。东西不多,但很考究,用信封里塑料套着,证书底下一块纸板,保证证书不褶皱,摸上去十分平整。一张证明通过认证的卡(现在什么都有卡,不知道是不是带芯片的)、一个SCJP徽章(很小,一不小心就会掉了)、一张证书、一封恭贺信、还有一份使用SCJP LOGO的协议书。最近看SCWCD(只是看看,如果它不出优惠价格,暂时不会想去考,也许等2年SCJP效力快过的时候去考一下),难度也颇低-_-b,像中国应试能力这么强的民族,应该是随考考的。

正看着SCJP LOGO协议,接到肖和立的电话说晚上六点上大ACM聚餐-_-b(4点出头),匆忙给陈胖子等人电话。衣毕,赶上公交前往。真是一年一度的聚餐,去年是殷老大主办的,今年由Larva主办。
晚上来的主要是前辈4人、我们这一届4人、学弟3人。大家因为ACM而聚在一起,虽然都不是很标准的ACM出生,但一起奋斗过,而且都是有能力有干劲的热血青年,而且除了ACM,我们之间也有许多开心或不开心的往事。餐桌上,学弟们说得很少,主要是前辈们给我们解就业之惑及讨论一些热点技术和未来问题。开头的主要新闻是梁老大的女朋友和他拿了Intel多线程比赛冠军,虽然他表现得很低调,但我抢着把他的事情抖了出来。然后谈论殷老大在SAP的经验,还是这么的健谈,学到了不少经验啊。李签的是SAP最大的partner之一,估计下次聚餐或许是小青年请或者是李和殷请啦。张大依然在为中国之崛起而奋斗,赞一下。肖的就业问题成了下一个讨论热点,我对肖的能力认可而不赞同,我和他的关系有点像在大学里我感觉他压着我,而他感觉我压着他。但我不认为我和他有对手关系,这样满无聊的,我觉得人只有把自己作为竞争对手才能发展得更健壮,所以我迫切希望脱离Larva(可能是暂时的)寻求下一个自我的突破点,所以我搬回了家。
ICPC的未来问题上,两位前辈始终在谈论计算机学院的老师和学生关系。而我觉得应该把上大ACM/ICPC推向全校,因为市场和资源在那里,而且只要能拉到赞助,再改变一点形式。这么高端的竞赛一定很有市场(其实就是奥林匹克从一个民族的运动发展到全世界运动的过程)。至于什么要尊重ACM/ICPC选手啦,ACM/ICPC就是尖子的比赛啦都是废话。竞赛的目的不是选尖,选尖是一种针对性很强的活动,大可不必花费如此多的人力就能选出顶尖的人才(比如直接办个招聘会什么的,写明编码速度要多快,算法熟练度要多高,然后拉批人现场考试就行了。更重要的,选尖要突出的是酬金,而不是奖状或什么荣誉,因为没有荣誉可言,对社会并没推动作用,纯粹是个人与主办方之间的事情)。竞赛的潜在意义是交流,特别是高端与低端的交流(因为容易产生鸿沟,就更需要交流)。而交流的目的是为了发展,通过竞赛给参赛者指定一个虚拟目标,所有参赛者为了目标而奋斗,当达到目标的时候社会就进了一步,竞赛可以衍生或扩展原目标。机器人足球竞赛其实是很成功的竞赛,如果50年后,真的能有机器人踢赢人,那它功不可莫,即使没有实现,他对推动人类进去也有重要作用,而他的参赛者都是走在时代前面的人。Topcoder也是很成功的,它的意义有两层,第一层是商业意义(商业是推动社会进步的最大源动力),第二层是他的交流平台,十分开放,对于培养人才相当有帮助。ACM/ICPC初衷很好,花这么大力气举办一次比赛无非是希望能有更多有才华的人加入进来,一起研究和讨论更高效更准确的算法或者代码实现方法。ACM现在不只是美国计算机协会,而是Association for Computing Machinery,就说明其实它的眼光十分远!这一点是美国值得我们学习的。

扯着扯着就扯远了,聚餐始终很愉快,聚餐结束的时候我忘记给各位拜早年了,乘新年还没来,在这里给所有上大ACM新老成员拜个早年,也给能耐心看完我blog的您拜个早年,祝新年身体健康、心想事成。

Tuesday, January 30, 2007

jlGui - Music Player

jlGui ( I guess that jlGui stands for jLayer's Gui ) 是一个java写的音乐播放软件,与当前主流媒体播放器当然还有差距,但其简便和小巧让我印象很深。

  1. 借助Java Web Start部署的应用,虽然很早就知道JWS的思想,也着实为这个idea感到钦佩,但真正的应用并不是很多还。而音乐播放器这一类的应用,用JWS部署是再好不过了!
    比如,我在blog上给个启动jlGui的服务,请确保安装了Java Web Start

    Select Skin (1/6): next
    Custom :
    Select Playlist (1/4): next
    Custom :
    Play Automaticly launch it!


  2. jlGui如其名,只是一个Gui,解码的任务由另一种服务提供(多好的功能分离啊,感动得流泪)。JavaSound集成在JRE中,其采用了SPI( Service Provider Interfaces )允许第三方以插件形式在其基本的JavaSound API下提供新的audio和MIDI资源。而jlGui有MP3SPI作MP3解码和VorbisSPI作OGG解码。

  3. jlGui皮肤采用winamp的皮肤,可以直接使用,但不保证一定好看(呵呵)。

  4. 正因为底层功能被分离了,jlGui本身很小很简单,能够方便地修改与调整。比如既然有JWS的版本,那么Applet自然也是可以的(Applet虽然曾经差点改变世界,但机会给Flash抢走了,所以现在的Applet并不是好选择)。如果开动想象力,应该还有很多种再开发的空间。

更多关于jlGui的信息在 http://www.javazoom.net/
同时,基于jLayer(jlGui的那个开发组的MP3SPI的底层项目)的一个eclipse播放器插件:
http://www.timbaumgartner.de/plugins.html

Monday, January 29, 2007

Google Talk using Gaim

这两天在ubuntu下唯一的不爽就是不能用Gaim上gtalk。不过之前我有给陈胖子和肖叉解决了这个问题。。。但现在居然忘记怎么解决了-_-b

好不容易等到陈胖子上线,问了才知道应该这么设置:
其实gtalk开放不少的端口,比如80,还有他们内部使用的一些

Saturday, January 27, 2007

ubuntu(edgy) xgl安装日记

先是试了好多方法都没能让显卡的3D加速跑起来,然后在ubuntu主页上的一篇文章下随便试了下,本想失败就放弃的,没想到成了~:
http://www.ubuntuforums.org/showthread.php?t=291464
以 deb http://www.beerorkid.com/compiz edgy main-edgy 资源为主

我的显卡是Radeon 9200。
第一步是安装ubuntu给ati显卡配的驱动fglrx:
$ sudo aptitude update
$ sudo aptitude dist-upgrade
$ sudo aptitude install xorg-driver-fglrx
# You will have to do this for every kernel update
$ sudo aptitude install linux-restricted-modules-`uname -r`
$ sudo cp /lib/modules/`uname -r`/volatile/fglrx.ko /lib/modules/`uname -r`/misc/fglrx.ko
$ sudo aptitude remove linux-restricted-modules-`uname -r`
$ sudo depmod -a
# If you know what you are doing, you can just edit xorg.conf manually to use fglrx
$ sudo aticonfig --initial
$ sudo aticonfig --overlay-type=Xv

$ sudo gedit /etx/X11/xorg.conf在xorg.conf添加:
Section "Extensions"
Option "Composite" "0"
EndSection

(补充一条自动检测显卡的命令 "sudo dpkg-reconfigure xserver-xorg")
选择一 重启
选择二 登出到控制台stop gdm, rmmod radeon and modprobe fglrx, 然后start gdm.

用 $ fglrxinfo 查看:
display: :0.0  screen: 0
OpenGL vendor string: ATI Technologies Inc.
OpenGL renderer string: MOBILITY/RADEON 9000 DDR Generic
OpenGL version string: 1.3.1091 (X4.3.0-8.28.8)

或者还有一个很好用的命令
$glxinfo | grep rendering
确定verdering string是ati而不是mesa!我起初就是这里错了。

第二步是安装xgl及一个用于OpenGL的管理工具(compiz或者beryl):
beryl可以从
deb http://ubuntu.beryl-project.org edgy main-edgy 获得
使用apt工具下载并安装其中一个。

第三步是配置:
先配置xgl运行脚本,创建"/usr/bin/startxgl"并添加内容

#!/bin/sh
Xgl :1 -fullscreen -ac -accel xv:pbuffer -accel glx:pbuffer &
DISPLAY=:1
exec dbus-launch --exit-with-session gnome-session

命令 "$ sudo chmod +x /usr/bin/startxgl" 使其可执行
再给xgl创建一个启动session,创建"/usr/share/xsessions/xgl.desktop":
[Desktop Entry]
Encoding=UTF-8
Name=Xgl
Comment=Start an Xgl Session
Exec=/usr/bin/startxgl
Icon=
Type=Application

随后登出,再用xgl的会话登入,然后开启安装的compiz-manager或beryl-manager就可以看到效果了。

郁闷啊,装了半天居然只能看两个效果,而且还时不时crack掉 -_-b。
显卡不行呀,虽然我几乎就是白装了,但希望这篇文章能对正在尝试给ubuntu装xgl的读者有所帮助。
个人觉得两个地方特别要花时间,一个是启动显卡的3D加速(可能NVIDIA会好一点),另一个是找compiz或者beryl的源。

蜜蜂的问题

老blog里比较不舍得丢的文章,移到这里来:

99ACM/ICPC final有一道蜜蜂的坐标的问题,非常有意思,和队友们讨论了许久都没能解决。记得那天做练习是我和肖筹划着用计算几何的方法估算出结果,虽然做法很独特,但毕竟是估算的,最后没有能过。后来我找了份解题报告,看到了解这类问题神奇地使用笛卡儿坐标,着实让人兴奋啊。所以准备了一份模板、数道类似问题和将蜜蜂坐标放在扫雷游戏里的应用,来一个蜜蜂问题的大汇总。


模板放在SHU ACM群里,含有一些处理正六边形拼成的坐标系的方法。

首先,蜂巢是由许多个正六边行无缝拼接而成的,这是一个美丽而奇特的自然结构,如图(图中程序是在解一道题时写的辅助程序,我也放在群与大家分享):


题外话,先来讨论下为什么六边形可以无缝的拼接出一个平面,那么七边、八边行不行?其实是一个简单的小学题: 正n边形内角为 (n-2)*180/n ,要保证可以无缝拼接,就是一个圆可以被整数个n边形内角拼接,即 360=k*(n-2)*180/n => 2n=k(n-2),用这个公式就能算一下是否正n边形能像六边行一样拼出一个平面了。


起初在遇到这样独特的结构时可能无法想象如何将其保存起来,可能会想到是不是做一个带六条链结点的链图?这样做的结果将是一个极难维护的链图,光是想到插入操作就起鸡皮疙瘩。


有一个十分巧妙的方法来储存这个怪异的结构:用二维数组。用二维数组保存四个方向或八个方向的东西肯定是很简单的,其实对于这个六向的结构,我们可以取二维数组的八向中的六向。即东、南、西、北、东北、西南(其实只要注意对称,六向可以随便取),这样相对的坐标向每个方向移动的偏移量就是:

西 东北 西南
x 1 0 -1 0 1 -1
y 0 -1 0 1 1 -1

到底正确与否呢,其实是必然正确的,只是我们损失了两个角(东南、西北),不过不碍事。通过上面这个方法不仅是保存了六边形的怪结构,而且也给这种结构指明了一个坐标表示的方法,在解题中这个概念很重要。


PKU 1134

与蜜蜂坐标没关系的题目,只是样子是六边行的。题目意思是给出三行,每行代表一个方向,然后可以按任意顺序把数字放在这个方向的任意一列中(以abcba的顺序分配到abc里)。归纳一下可以得到以下结论, 最大的得分就是三行分别乘以下面的系数:

1a * 8 + b * 6 + c * 5
2a * 7 + b * 7 + c * 5
3a * 7 + b * 7 + c * 5 。所以枚举一下就可以求出最大值了。


PKU 2265

这是非常简单、易上手的题目,熟悉两种坐标系对于解决蜜蜂问题很有帮助,这两个坐标系也是蜜蜂最常用的坐标,转换的方法就是直接上模板。


PKU 1870

99FINAL的题目,除了用模板里的构造点来构造一个六边形结点(带XY轴坐标)以外,模板里有求两点间最短距离的函数。


求最短距离要以一点为原点,即用一点减去另一点的XY坐标。然后对相对的那个点的两种情况做处理:xy同正同负时,距离是max(|x|,|y|);否则距离为距离是|x-y|。简单得想象一下就知道了。


PKU 1792

1870的升级版,除了要求最短的距离外,还需要求两个点间有多少种路径可以用最短的距离。其实求可能的路径数可以归约为求组合数的问题:


上图为例,在x>0 y>0的区域,最短距离是max(|x|,|y|),图中某点的最短距离很明显是 |x|,然后如何求路径数呢?这样思考,为了能到达那个点,所有路径在两点之间准没错吧(出了两点间的区域就不能最短距离了)。那在最短路径为d的情况下,取d中的一点让它或上或下(只要保证还在两点间的那块区域),不就可以得到一条新的路径?这样,在d中取c个点(c为最大的可变的点,或称关节),就是总路径数。那么总的路径数就是combine(d,c)了。巧合的是c的值情况与最短路径的值情况正好相反,即xy同正同负时,c|x-y|;否则cmax(|x|,|y|)

模板里有个函数实现此功能,不过自己写写也很简单的吧。


PKU 3036

哈,在1792有点类似,不过做法完全不一样的题。求的是从原点出发到达距离为n的地方再回来的路径数。其实知道用动态规划和前面讲的六个方向的坐标的话,这道题目是非常简单的。动规方程见下:


dp[i][x][y] i表示距离原点i步;xy是点的坐标。

 dp[i][x][y]=  dp[i-1][x+1][y] + dp[i-1][x-1][y] + dp[i-1][x][y+1] +dp[i-1][x][y-1] + dp[i-1][x-1][y-1] + dp[i-1][x+1][y+1]
初始dp[0][x][y]都为0dp[0]原点为1。然后开始dp,最后dp[i]原点就是第i步的解。

上面的是比较简单的或基于六向的坐标系的,下面两道比较有意思,是对于此类坐标系的扩充:


PKU 1957

那个辅助程序就是我为了做这道题目而写的,用法是先输入walk,然后按lrotate可左转(正规化过)。

题目的解法很容易想到的,就是先将走过的点放在一个set里,然后做旋转和正规化,直到两个set的元素都相等为止。

依照行走的路线构造点不是件难事,从原点出发。旋转是比较费神的,正规化的话其实就是找出一个最左最右的点作为参照点,所有点减掉它就行了。

旋转可以从两个角度考虑,一是考虑求出了点之后做旋转,二是考虑在将行走路线做旋转然后求点。如果从前种方向考虑的话,会很累,在简单的四向的坐标系中点相对于原点的转动可以通过乘以一个变换矩阵得到,而对于一个六向的坐标系,举个例子:

一个二维数组保存的七个点(O表示该位置无值,X表示该位置是一个六边形结点):

O X X               X X O
X X X ===========> X X X
X X O 乘以变换矩阵 O X X

很明显,旋转后的不是原来使用的六向的坐标表示方法了。当然,调整变换矩阵的话,相信还是有办法解决的,但这毕竟是个较麻烦的活儿。

那么从后者的方向来考虑的话,事情就简单了很多。见下图:

按行走路线进行转换的思想就是上图所表现的,显而易见了吧。代码实现也是相当的简单。即将把原来的a方向的操作改为b方向操作等等。

这样的话,先输入第一种走法,正规化一下。然后输入第二种,做七次旋转(包括不转的那种),每次正规化后再比对两个集合就行了。

PKU 1518

看上去很吓人的题目,跟计算几何又有关系,而且坐标系又是要六向的表示。Take it easy,先来看看一个扫雷游戏吧:


在扫雷游戏中有这样一个问题,鼠标点击了之后要出发事件,事件的参数只有鼠标点击的点的坐标(x,y)。求鼠标点击的是哪块雷区,知道了哪块雷区才可以做相应操作嘛。


通过平面坐标求六边形的坐标的方法其实满多的,在这里介绍一个简单的方法:


首先,要判断点是否在六边形内,经常使用的是用叉乘判断点对于凸边形的每个顶点是左转还是右转可以做到。不过这里不需要这么做,因为六边行都是紧凑得在一起,而且都是正多边形,所以求一下点到每个多边形中心的距离,然后取最小值可以找到它所在的六边形了(如果正好在边上,随便取哪个都一样)。


为了优化一点,不用对每个六边形都求一下它的中心与目标点的距离。可以先从距离估算出目标点的大致位置,然后包括大致位置的六边形在内,相邻的六个六边形再确定出最终点所在的六边形。


估算的方法是简单的计算几何(d是六边形边长,tdsqrt(3)*d/2p是目标点):

x = (int) Math.round((p.x * 2 / (3 * d)));
y = (int) Math.round(((-p.y + x * td) / (2 * td)));

知道了六边行的坐标,接下来的事情就容易了。求两坐标间最短路径,然后路径乘以2*td。再将具体的两个点与六边形中心的距离相加。就是结果了,当然要注意在同一个六边形内的两点是直接计算两点距离。


链接:

Ray's Blog: http://raythking.blogspot.com/
SHU-ACM-Group: http://groups-beta.google.com/group/shu-acm-group
Mineray: https://mineray.dev.java.net/