集训第七天了。心里有些感慨
有些想家了。给家里打了电话,我想也快了把,就要回到开化了。想来,已经半年不在开化了,整整半年。
今天写了两道题,一个是poj2559,一个事poj1751
poj2559:维护一个单调栈。
如果后期有空我会贴点报告。现在只贴个代码把。
核心思想在于,利用单调栈,找出每个pop的元素的最大可拓展边界,把复杂度从o(n^2)弄到o(n)
代码如下:
#include <cstdio> #include <iostream> using namespace std; #define MAXSIZE 1000000 /* * poj2559,维护一个单调栈就可以了。 * 第一次用栈,逻辑不是很清楚 * 大概这样:每次弹出元素的时候,计算这个元素形成的面积。跟最值比较。 * 再写点,,之前弄懂后来又忘了。 * 就是,每次出栈,栈顶元素肯定是不比他在栈里下面那个元素低的,这是他能拓展的左边最长的地方 * 既然出栈,必然新的元素比栈顶元素低,因为出栈元素无法向右拓展(新的元素是第一个让他无法拓展的元素) * 这样就能求出他能拓展的最大面积了。 * new.index-stack[top-1].index-1就是宽度*stach[top].height就行了 * (new.index-stack[top].index) + (stack[top].index-stack[top-1].index) * */ typedef struct{ int index; long long height; }node; node stack[MAXSIZE]; int top; node pop() { top--; return stack[top+1]; } void push(node x) { top++; stack[top] = x; return; } void initialise() { node t; t.index = 0; t.height=-1; top=0; push(t); return; } node getTop() { return stack[top]; } int main() { int N; int i,j,k; node t,curNode; long long ans; long long curAns; while(scanf("%d",&N),N!=0) { ans = -1; initialise(); for(i=1;i<=N+1;i++) { if(i==N+1) { t.index = N+1; t.height=-1; } else { scanf("%lld",&t.height); t.index=i; } while(getTop().height > t.height) { curNode = pop(); /* printf("pop the node, Index:%d,Height:%d ",curNode.index,curNode.height);*/ curAns = (long long)(t.index - getTop().index -1) * (curNode.height); /*printf("i:%d,curAns:%d ",i,curAns);*/ if(curAns > ans) ans = curAns; } push(t); /*printf("push the node which index is %d height is%d ",t.index,t.height);*/ /* * 别忘了把所有元素pop出来。否则会漏掉计算 * */ } cout<<ans<<endl; } return 0; }
然后是poj1751,,一个最小生成树。。
同上,,后期如果写结题报告会加入传送门。
现在只贴代码。
记录一点,显然是prim,但是关键在于,,把已经修好路的点之间距离设为0
但是!,但是!,还是一样的prim,
绝对不是把那些已经修好的路直接标记成visited,这点很重要。
我们应该做的是,把距离改成0,然后按照prim的流程正常进行求最小生成树。
记得用一个pre数组,在更新low数组的时候,这个数组可以更新跟他连接的最短边的另一个定点
AC代码如下:
#include <stdio.h> #include <math.h> #define INF 300000000 typedef struct{ int x; int y; }node; node nodes[751]; double a[751][751]; double low[751]; int vis[751]={0}; int pre[751]={0}; /*----------------------------------------------------------------------------- * 计算距离。 *-----------------------------------------------------------------------------*/ double calcDistance(node *i,node *j) { return (sqrt( ( (*i).x-(*j).x)*((*i).x-(*j).x) + ((*i).y-(*j).y)*((*i).y-(*j).y) )); } int main ( int argc, char *argv[] ) { node n; int N,M; int i,j,k; scanf("%d",&N); for(i=1;i<=N;i++) { scanf("%d%d",&n.x,&n.y); nodes[i] = n; } for(i=1;i<=N;i++) { for(j=1;j<i;j++) { a[i][j] = calcDistance(&nodes[i],&nodes[j]); a[j][i] = a[i][j]; } } scanf("%d",&M); int x,y; for(i=1;i<=M;i++) { scanf("%d%d",&x,&y); a[x][y]=a[y][x] = 0; } /* for(i=1;i<=N;i++) { for(j=1;j<=N;j++) { printf("%lf ",a[i][j]); } printf(" "); }*/ int pos=0; int flag; for(i=1;i<=N;i++) { low[i] = INF; pre[i] = 1; } vis[1] = 1; for(i=2;i<=N;i++) { if(a[1][i] < low[i]) { low[i]=a[1][i]; } } double min; /* 开始定义成了int类型的min.真是作死,,其实,low和a数组都不需要int,,根本不需要开根号 */ while(1) { /* for(i=1;i<=N;i++) { printf("vis[%d]:%d low[%d]:%lf pre[%d]:%d ",i,vis[i],i,low[i],i,pre[i]); }*/ flag = 1; for(i=1;i<=N;i++) { if(vis[i] == 0) flag = 0; } if(flag) break; min = INF+1; for(i=1;i<=N;i++) { if(vis[i]==0 && min>low[i]) { min = low[i]; pos = i; } } vis[pos] = 1; if(a[pos][pre[pos]] != 0) printf("%d %d ",pre[pos],pos); /* 然后根据pos更新low数组 */ for(i=1;i<=N;i++) { if(vis[i]==0 && a[pos][i] < low[i]) { pre[i] = pos; low[i] = a[pos][i]; } } } return 0; } /* ---------- end of function main ---------- */
当然,其实不需要做sqrt,因为不需要真的计算,只需要比较,,这是多余的
因此low和邻接矩阵其实不用开double数组。
今天和别人聊天,所以晚了点,就只写这么些把。。今天的另外一个收获是看懂了quickSort并且自己写了个。
然后看了看qsort的使用方法。