2016.8.28测试解题报告(buylow,line,brush)

原创 2016年08月30日 20:25:36

好吧,好久不见!

1.低价购买

问题描述:
“低价购买”这条建议是在奶牛股票市场取得成功的一半规则。要想被认为是伟大的投资者,你必须遵循以下的问题建议:“低价购买;再低价购买”。每次你购买一支股票,你必须用低于你上次购买它的价格购买它。买的次数越多越好!你的目标是在遵循以上建议的前提下,求你最多能购买股票的次数。你将被给出一段时间内一支股票每天的出售价(216范围内的正整数),你可以选择在哪些天购买这支股票。每次购买都必须遵循“低价购买;再低价购买”的原则。写一个程序计算最大购买次数。
这里是某支股票的价格清单:
日期 1 2 3 4 5 6 7 8 9 10 11 12
价格 68 69 54 64 68 64 70 67 78 62 98 87
最优秀的投资者可以购买最多4次股票,可行方案中的一种是:
日期 2 5 6 10
价格 69 68 64 62

思路:
题目意思很明显,我们需要求一个序列的最长下降子序列,并且,我们需要求它的方案总数。首先,我们可以设f[i]表示以i结尾的最长下降子序列的长度为多少,那么:
F[0] = 0
F[i] = max{f[j]}+1 (j < i 且 a[j]>a[i])
这个方程的时间复杂度为O(n^2)。
为了记录方案数,我们可以设g[i]表示以i结尾的最长下降子序列的方案数为多少,那么:
g[0] = 0
g[i] = Ʃg[j]
但是题目中要求当方案看起来一样时,需要算作同一个方案,所以上面的所有j中a[j]相同的,我只要取j值最大的即可。
最后总时间复杂度为O(n^2)。

代码:

/*
2016.8.30 BulaBulaCHN
*/
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<string>
#include<cstring>
#include<iostream>
using namespace std;
int a[5005];
int n;
int f[5005];
int g[5005];
int ans,an;
int main()
{
    freopen("buylow.in","r",stdin);
    freopen("buylow.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    a[0]=2147483647;
    for(int i=1;i<=n;i++)
        for(int j=0;j<=i-1;j++)
        if(a[i]<a[j]) f[i]=max(f[i],f[j]+1);
    g[0]=1;
    for(int i=1;i<=n;i++)
        for(int j=i-1;j>=0;j--)
        {
            if(a[i]<a[j] && f[j]+1==f[i]) g[i]+=g[j];
            if(a[i]==a[j]) break;//结尾相同的我们只取一遍,既最大值
        }
    for(int i=1;i<=n;i++) if(f[i]>ans) ans=f[i];
    int tot=0;
    for(int i=1;i<=n;i++) if(f[i]==ans) tot+=g[i];
    cout<<ans<<" "<<tot<<endl;
    fclose(stdin);
    fclose(stdout);
    return 0;
}

2.通讯线路

问题描述:
某地区共有n座村庄,每座村庄的坐标用一对整数(x, y)表示,现在要在村庄之间建立通讯网络。通讯工具有两种,分别是需要铺设的普通线路和卫星设备。卫星设备数量有限,只能给k个村庄配备卫星设备。拥有卫星设备的村庄互相间直接通讯;铺设了线路的村庄之间也可以通讯。卫星分配是不受限制的。
问怎样合理的分配卫星和铺设线路,使得在保证每两座村庄之间都可以直接或间接地通讯的前提下,铺设线路的总长度最短。

思路:
看到这道题就应该想起来最小生成树,不过如果这道题按照最小生成树的答案输出的话就会忽视卫星的存在。因为卫星可以连接k个联通分量既k棵树,所以我们只要先用Kruskal做一遍最小生成树,再删掉k-1条边权最大的边就可以了。具体实现的时候可以直接选择n-k条最小的边达到相同的目的。具体证明同Kruskal算法。

代码:

/*
2016.8.30 BulaBulaCHN
*/
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<string>
#include<cstring>
#include<iostream>
using namespace std;
struct point
{
    int x,y;
}a[2005];
struct Edge
{
    int x,y;
    int val;
}eage[4004005];
int tot=0;
int cacl(point a,point b)
{
    return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}
void add(int x,int y,int v)
{
    eage[++tot].x=x;
    eage[tot].y=y;
    eage[tot].val=v;
}
bool cmp(Edge a,Edge b) {return a.val<b.val;}
int f[2005];
int findx(int x)
{
    int r=x;
    while(f[r]!=r)
        r=f[r];
    return r;
}
int n,k;
int top=0;
int tim=0;
double ans=0;
int main()
{
    freopen("line.in","r",stdin);
    freopen("line.out","w",stdout);
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++) scanf("%d%d",&a[i].x,&a[i].y);
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++)
        if(i!=j) add(i,j,cacl(a[i],a[j]));
    for(int i=1;i<=n;i++) f[i]=i;
    sort(eage+1,eage+1+tot,cmp);
    while(1)
    {
        top++;
        int g1=findx(eage[top].x);
        int g2=findx(eage[top].y);
        if(g1!=g2)
        {
            f[g2]=g1;
            tim++;
            ans+=sqrt(eage[top].val);
            if(tim==n-k) break;
        }
    }
    printf("%.4llf",ans);
    fclose(stdin);
    fclose(stdout);
    return 0;
}

3.粉刷墙壁

问题描述:
现在需要粉刷一列墙壁,墙壁被分成n段,为了节约用钱,科学家决定只粉刷其中一些段,同时为了美观,科学家要求每连续的m段墙壁中至少有两块被粉刷,现在已知粉刷每一段墙壁的费用。科学家要你帮他求出最少的费用。

思路:
一眼dp。可以先假设第0块墙壁和第-1块墙壁已经被粉刷过了,所以说可以设状态为:满足第i块墙壁之前的所有墙壁段的要求,且粉刷的最后一块墙壁是第i块、粉刷的倒数第二块墙壁是第i-j块的方案的最低花费为f[i][j]。则有状态转移方程:f[i][j]=min(f[i-j][k])+a[i](既假设粉刷的最后一块墙壁是第i块,枚举所有可以满足条件的状态)

代码:

/*
2016.8.30BulaBulaCHN
*/
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<string>
#include<cstring>
#include<iostream>
using namespace std;
int n,m;
int a[10005];
int f[10005][105];
int ans=0x3f3f3f3f;
int main()
{
    freopen("brush.in","r",stdin);
    freopen("brush.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    memset(f,0x7f,sizeof f);
    for(int i=2;i<=m;i++)
        for(int j=1;j<i;j++)
        f[i][i-j]=a[i]+a[j];
    for(int i=m+1;i<=n;i++)
        for(int j=i-m+1;j<=i+1;j++)
    {
        for(int k=i-m;k<j;k++)
            f[i][i-j]=min(f[i][i-j],f[j][j-k]);
        f[i][i-j]+=a[i];
    }
    for(int i=n-m+1;i<=n;i++)
        for(int j=i+1;j<=n;j++)
        ans=min(ans,f[j][j-i]);
    printf("%d",ans);
    fclose(stdin);
    fclose(stdout);
    return 0;
}
版权声明:本文为博主原创文章,禁止所有形式的未经博主允许的转载行为。

相关文章推荐

CTU 2012解题报告(测试数据)

  • 2013-03-18 19:09
  • 12.61MB
  • 下载

解题报告1 Max Points on a Line

题目: Given n points on a 2D plane, find the maximum number of points that lie on the same straight li...

ctsc解题报告和测试数据。

  • 2007-07-08 08:48
  • 8.29MB
  • 下载

【LeetCode】Max Points on a Line 解题报告

【题意】 求二维平面上n个点中,最多共线的点数。 【思路】 比较直观的方法是,三层循环,以任意两点划线,判断第三个点是否在这条直线上。 【Java代码】 /** * Definition for a...

URAL 1019 Line Painting(解题报告)

Description The segment of numerical axis from 0 to 109 is painted into white color. After that...

LeetCode—Max Points on a Line解题报告

原题如下: 最先想到的做法就是每次固定一个点,然后计算它同其他所有点的斜率,并且对出现过的斜率进行累加计数。做的时候,需要注意几点:1、直线不存在的时候,也就是斜率不存在  2、有重复的点出现。算...

LeetCode Max Points on a Line 解题报告

Max Points on a Line 解题报告 http://oj.leetcode.com/problems/max-points-on-a-line/ 给你一组点,求共线最多点的个数。 思路,...

解题报告 之 HOJ2816 Power Line

解题报告 之 HOJ 2816 Power Line 最大流 二分
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)