• 140705


    集训第七天了。心里有些感慨


    有些想家了。给家里打了电话,我想也快了把,就要回到开化了。想来,已经半年不在开化了,整整半年。


    今天写了两道题,一个是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的使用方法。

  • 相关阅读:
    【转载】常考算法模板
    NOIP2020微信步数暴力80分
    NOIP2020移球游戏快速排序满分程序
    第一场NOI Online能力测试入门组B跑步
    【转】STL之Set——插入元素、二分查找元素(log级别)
    [转载]图论500题
    差分约束系统简单介绍(入门)
    辗转相除法的证明
    并查集2个优化——按秩合并和路径压缩
    递推算法之平面分割问题总结
  • 原文地址:https://www.cnblogs.com/shengrang/p/3843484.html
Copyright © 2020-2023  润新知