|
|
|
|
|
|
发新文章 |
|
|
2010年2月27日
寒假回家还是学了很多知识的,巩固了之前自己一直不常熟练的图论的一些算法,搜索算法,最短路算法和生成树算法,感觉还是有很大的收获,但是发现一些问题,首先,自己对于数据结构上的问题还是很生疏,例如处理大规模的图结构的时候对于邻接表的书写还是很陌生,需要学习的地方,还有就是很多算法的优化都要用到数据结构中的知识,所以回到学校要赶快学习数据结构的了。第二,虽然自己书写算法的思路有一定的清晰度了,但是对于代码的长度却很纠结,一个STL的BFS居然都能写到4000B+,不晓得是怎么回事的了,多看看别人的代码,看看别人是怎么提高代码的效率的。回到学校了以后,除了学习数据结构以外,补上关于求前连通分量,图匹配的问题。图论想先放一放的了,多看看书,有空的时候切切题,下学期空闲的时候比较多,应该可以切多点题的吧。
回学校前的最后一晚上写了一道题,又是4000B+。。。。MST+PRIM(POJ3026)同化所有的外星人,看成一堆人去同化外星人,同化了外星人后分开去同化其他的外星人,就是求所有节点的MST的权值。自己的代码跑了43MS,应该还可以得到优化,在求解DIS数组的时候,可以降低复杂度,毕竟这个矩阵是个对称阵的,剩下自己也没想的了,加上一个判断就可以解决的了。
 代码
//MST+BFS 要是不看DISSCUSS 估计又是WA。。。
#include<iostream> #include<queue> using namespace std ;
typedef struct node_p{ int x0 , y0 , step ; }node ;
const int maxn = 55 ; const int maxm = 105 ; const int INF = 1000000000 ;
char temp[10000] ; int map[maxn][maxn] , dis[maxm][maxm] , d[maxm] , d_flag[maxm] ; int x , y ; //x__col y__row node cur_node ,de_node; int dir[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};
void BFS( int cur_x , int cur_y ,int count ){ int p_num , flag[maxn][maxn] ; queue<node>q ; memset(flag , 0 , sizeof(flag)) ; p_num = 0 ; cur_node.x0 = cur_x ; cur_node.y0 = cur_y ; cur_node.step = 0 ; flag[cur_x][cur_y] = 1 ; q.push(cur_node) ; // start-point pushed
while(!q.empty()){ cur_node = q.front() ; q.pop() ; /*printf("cur_node.x0 == %d ",cur_node.x0); printf("cur_node.y0 == %d ",cur_node.y0); printf("cur_node.step == %d\n ",cur_node.step);*/ if( map[cur_node.x0][cur_node.y0] != 0 && map[cur_node.x0][cur_node.y0] != -1 ){ dis[map[cur_x][cur_y]][map[cur_node.x0][cur_node.y0]] = cur_node.step ; dis[map[cur_node.x0][cur_node.y0]][map[cur_x][cur_y]] = cur_node.step ; p_num ++ ; if(count == p_num) break ; } //update for( int i = 0 ; i < 4 ; i++ ){ int px , py ; px = cur_node.x0 + dir[i][0] ; py = cur_node.y0 + dir[i][1] ; if(flag[px][py] == 0 && px>=0 && px<y && py>=0 && py<x && map[px][py] != 0 ){ de_node.x0 = px ; de_node.y0 = py ; de_node.step = cur_node.step + 1 ; flag[px][py] = 1 ; q.push(de_node) ; } } } }
int main(){ int T , i , j , count ; scanf("%d",&T) ; while( T-- ){ scanf("%d%d",&x,&y) ; gets(temp) ; //for useless space_char memset(map , 0 , sizeof(map)) ; memset(d_flag , 0 , sizeof(d_flag)) ; count = 0 ;
for( i = 0 ; i < y ; i++ ){ gets(temp); for( j = 0 ; j < x ; j++ ){ if(temp[j] == '#') map[i][j] = 0 ; else if(temp[j] == ' ') map[i][j] = -1 ; else if(temp[j] == 'A'||temp[j] == 'S'){ count ++ ; map[i][j] = count ; } } }
//BFS to get_dis for( i = 0 ; i < count ; i++ ){ for( j = 0 ; j < count ; j++ ){ dis[i][j] = INF ; } } for( i = 0 ; i < y ; i++ ){ for( j = 0 ; j < x ; j++){ if(map[i][j] != 0 && map[i][j] != -1 ) BFS(i , j , count) ; } } //debug.. /*for( i = 1 ; i <= count ; i++ ){ for( j = 1 ; j <= count ; j++ ){ printf("%d ", dis[i][j]); } printf("\n"); }*/ //prim to get MST_ans ; int ans ; ans = 0 ; d_flag[1] = 1 ; for( i = 1 ; i <= count ; i++ ) d[i] = dis[1][i] ; for( i = 2 ; i <= count ; i++ ){ int min_node = 0 ; int minlen = INF ; for( j = 1 ; j <= count ; j++ ){ if( minlen > d[j] && d_flag[j] == 0 ){ min_node = j ; minlen = d[j] ; } } if(min_node != 0 ){ //printf("minlen = %d\n",minlen) ; d_flag[min_node] = 1 ; ans += minlen ; //printf("ans = %d\n" , ans) ; for( j = 1 ; j <= count ; j++ ){ if(d[j]>dis[min_node][j]) d[j] = dis[min_node][j] ; } } else break ; } printf("%d\n",ans) ; } return 0; }
posted @ 2010-02-27 02:04 Jpretty 阅读(35) 评论(0) 编辑
2009年10月4日
在市里面的呢。。旁边又没IDE。。看了这道题。。打表法。这个是DISCUSS的算法的哦,不是原创,不过学习约瑟夫环问题,顺便学习链表数据结构。看后续的文章的了。 PS:打表好邪恶。。。其实很多的题在数据不大的情况下可以先本地打表,然后再过。。。好邪恶。。 #include<iostream>
using namespace std;
int array[14]={2,7,5,30,169,441,1872,7632,1740,93313,459901,1358657,2504881,13482720};
int main()
{
int k;
cin>>k;
while(k!=0)
{
cout<<array[k-1]<<endl;
cin>>k;
}
return 0;
}
posted @ 2009-10-04 23:55 Jpretty 阅读(438) 评论(0) 编辑
2009年9月21日
威佐夫博弈(Wythoff Game)这个是完全的博弈论的知识然后只要参考知识写出代码就可以的了。
有两堆各若干个物品,两个人轮流从某一堆或同时从两堆中取同样多的物品,规定每次至少取一个,多者不限,最后取光者得胜。 如果甲面对(0,0),那么甲已经输了,这种局势我们称为奇异局势。前几个奇异局势是:(0,0)、(1,2)、(3,5)、(4,7)、(6,10).可以看出,a0=b0=0,ak是未在前面出现过的最小自然数,而 bk=ak+k.
那么任给一个局势(a,b),怎样判断它是不是奇异局势呢?我们有如下公式:
ak =[k(1+√5)/2],bk= ak + k (k=0,1,2,...,n 方括号表示取整函数)
奇妙的是其中出现了黄金分割数(1+√5)/2 = 1。618...,因此,由ak,bk组成的矩形近似为黄金矩形,由于2/(1+√5)=(√5-1)/2,可以先求出j=[a(√5-1)/2],若a=[j(1+√5)/2],那么a = aj,bj = aj + j,若不等于,那么a = aj+1,bj+1 = aj+1+ j + 1,若都不是,那么就不是奇异局势。然后再按照上述法则进行,一定会遇到奇异局势。
#include<stdio.h> int main() { int n,m,swap; int k; double r=0.6180339887,R=1/r; while(scanf("%d%d",&a,&b)==2) { if(n>m){ swap=n; n=m;m=swap;} k=n*r; if(n!=(int)(k*R)) ++k; printf("%d\n",m!=(int)(k*R)+k); }
return 0; }
posted @ 2009-09-21 22:58 Jpretty 阅读(536) 评论(0) 编辑
博弈问题,代码量很少的呢,不过题目中间的思想才是重点的。
#include<stdio.h> int count; void match(int a,int b) { int swap; if(a<b){ swap=a; a=b; b=swap; } if(a==b) return; //如果两组数相等,那么面对这个局势的人获胜 if(a/b>=2) return; //如果面对此局势,是必胜的,代码后有注解 else {count++; match(a-b,b);
} }
int main() { int a,b; while(scanf("%d%d",&a,&b)!=EOF) { if(a==0&&b==0) return 0; count=0; //这个是定义了如果每个人都采用PREFECT的战略的话,到达这个必胜的局面时经过的轮数 match(a,b); //printf("count==%d\n",count); if(count%2) //如果是奇数轮的话那么后拿的那个人获胜 printf("Ollie wins\n"); else printf("Stan wins\n"); } return 0; } a/b>=2,面对这个局势的时候,a=b*k+q,那么可以看做a是由k堆b再加上q组成的,那么如果取走全部的K堆的时候得到的如果是必败的战略,那么面对这个局势的人获胜,如果取走全部的K堆得到的是必胜的战略,那么这个人完全可以取走k-1堆b,让接下来的这个人去面对这个必败局势,所以这个情况也是。所以这道题就没问题的了。
posted @ 2009-09-21 22:30 Jpretty 阅读(86) 评论(0) 编辑
2009年9月12日
自己发觉一个人搞这些真的很难的呢,而且在我们学院的,搞ACM的人很少的说,没事得,多发展点人来搞,大家都是新手的额,多个人可以多问下,多讨论,也不会觉得很孤单地了嘛。。。。。希望这个组织能搞下去,为了参加大二下的校赛的目标。改天去问问砾哥看他有时间的没哎,要是有的话把他拖来给我们讲,嘿嘿。。。。。要是没时间就算了的哦。。。 今天A了一道水题,很简单的,代码就不贴的了,现在做这样的DFS题有心得的了呢,三段,main,begin,DFS,直接出结果。 自己的大学到底是为了什么的呢,不能天天宅宿舍的了。。。每周初星期四以外的所有的晚上都要上晚自习的了。。。。星期四是CODING时间。。。。~~
posted @ 2009-09-12 23:03 Jpretty 阅读(63) 评论(2) 编辑
2009年9月2日
#include<iostream> using namespace std; int cake[11],pos[41]; //题目限制的是蛋糕的最大变长为10,且需分割的最大边长为40 int m,k;
bool DFS(int a) { int i,min_pos=41,lie=0,j,t; if(a==k) //如果遍历到放入的数目和要求的数目相同即完成目标 return true; for(i=1;i<=m;i++) if(pos[i]<min_pos){ min_pos=pos[i]; //找到了在竖直方向上用去的最短行数 lie=i; } for(i=10;i>=1;i--){ if(cake[i]&&min_pos+i<=m&&lie+i-1<=m){ //可以放入边长为I的正方形 for(j=lie;j<=lie+i-1;j++) if(pos[j]>min_pos) //该空隙的宽度大于等于i break; if(j>lie+i-1){ cake[i]--; //这个就是典型的DFS算法的了 for(t=lie;t<=lie+i-1;t++) pos[t]=pos[t]+i; if(DFS(a+1)) return true; //I GET THE WA HERE  cake[i]++; //回溯部分的算法 for(t=lie;t<=lie+i-1;t++) pos[t]=pos[t]-i; } } } return false; }
int main() { int n,sum_cake,ori_cake,i,s; //sum_cake为要做的蛋糕的总面积,ori_cake为给的蛋糕的总面积 scanf("%d",&n); while(n--){ memset(cake,0,sizeof(cake)); memset(pos,0,sizeof(pos)); scanf("%d%d",&m,&k); sum_cake=0; ori_cake=m*m; for(i=1;i<=k;i++){ scanf("%d",&s); cake[s]++; sum_cake=sum_cake+s*s; } //printf("sum_cake==%d,ori_cake==%d\n",sum_cake,ori_cake); if(sum_cake!=ori_cake) printf("HUTUTU!\n"); else if(DFS(0)) printf("KHOOOOB!\n"); else printf("HUTUTU!\n"); } return 0; }
//感觉挺好的一道题,DFS部分用得很经典,关键部分是找到放正方形的策略,每次寻找到单行的最短行数,由大的开始放 //还有没有其他的方法的呢,这种做法始终让人不是很放心,这样的放置方式可以任一情况下都行吗?
posted @ 2009-09-02 00:22 Jpretty 阅读(418) 评论(0) 编辑
2009年8月31日
摘要: [代码]联系BFS。。居然写出了一段DFS代码。。。。明天写下这道题的BFS的吧。。比较下算法。。。400MS过,悲哀呢。。。 阅读全文
posted @ 2009-08-31 23:51 Jpretty 阅读(45) 评论(2) 编辑
2009年8月30日
摘要: #include<stdio.h>#include<string.h>int n1, n2; bool prim[10000]; int value[10000]; int q[11000]; int c[4]= {1, 10, 100, 1000};void prime(){ int i,j; prim[0]=prim[1]=false; for(i=2;i<500... 阅读全文
posted @ 2009-08-30 21:55 Jpretty 阅读(195) 评论(0) 编辑
2009年8月28日
摘要: 还是DFS。。。。真好用的呢。。开这么大的规模的数组时间都不超过150MS。。。。。125MS过。可以剪枝的吗,觉得找不到剪枝的地方的呢。[代码]在家里的最后一道题的了,很简单的一道题的呢,对DFS有比较初步的理解的了,砾哥说还有维护一个栈的DFS写法。。回学校了再研究的吧。回学校了开始入门BFS,一样一样来的嘛,不着急。。PS:这个农场可够大的。。。。。 阅读全文
posted @ 2009-08-28 16:30 Jpretty 阅读(204) 评论(0) 编辑
摘要: 这道题的思路不是很难的吧,也是DFS就可以解决的,不过输入的时候为什么要用字符串输入的呢,不懂,但是我用SCANF就不行的嘛,还是纠结的,看了DISCUSS,过了,但1426MS,代码就不贴了嘛,据说有反着搜的方法,去看看再说的。用数组来表示当前组什么数字用过的是能节约时间的了。for(i=1;i<=9;i++) for(j=1;j<=9;j++){ soduku[i][j] = c[... 阅读全文
posted @ 2009-08-28 15:07 Jpretty 阅读(43) 评论(0) 编辑
|
|