集训第七天了。心里有些感慨
有些想家了。给家里打了电话,我想也快了把,就要回到开化了。想来,已经半年不在开化了,整整半年。
今天写了两道题,一个是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的使用方法。