完全为了应付而交的CCF

 

实验名称

实验六 窗口

实验内容

  在某图形操作系统中, N 个窗口,每个窗口都是一个两边与坐标轴分别平行的矩形区域。窗口的边界上的点也属于该窗口。窗口之间有层次的区别,在多于一个窗口重叠的区域里,只会显示位于顶层的窗口里的内容。
  当你点击屏幕上一个点的时候,你就选择了处于被点击位置的最顶层窗口,并且这个窗口就会被移到所有窗口的最顶层,而剩余的窗口的层次顺序不变。如果你点击的位置不属于任何窗口,则系统会忽略你这次点击。
  现在我们希望你写一个程序模拟点击窗口的过程。

实验要求

输入格式

  输入的第一行有两个正整数,即 N 和 M。(1 ≤ N ≤ 10,1 ≤ M ≤ 10)
  接下来 N 行按照从最下层到最顶层的顺序给出 N 个窗口的位置。 每行包含四个非负整数 x1, y1, x2, y2,表示该窗口的一对顶点坐标分别为 (x1, y1) 和 (x2, y2)。保证 x1 < x2,y1 2。
  接下来 M 行每行包含两个非负整数 x, y,表示一次鼠标点击的坐标。
  题目中涉及到的所有点和矩形的顶点的 x, y 坐标分别不超过 2559 和  1439。

输出格式

  输出包括 M 行,每一行表示一次鼠标点击的结果。如果该次鼠标点击选择了一个窗口,则输出这个窗口的编号(窗口按照输入中的顺序从 1 编号到 N);如果没有,则输出"IGNORED"(不含双引号)。

主要仪器设备

台式或笔记本电脑

实验记录(写出实验内容中的程序代码和运行结果)(可分栏或加页)

 #include<iostream>

#include<cstring>

#include<algorithm>

#include<vector>

using namespace std;

const int maxn=1000;

struct Node

{

    int x1,y1;

    int x2,y2;

    int in;

}N[10];

 

int main(void)

{

    int n,m;

    int i,j,k;

    int x,y;

    while(cin>>n>>m)

    {

        for(i=0;i<n;i++)

        {

            cin>>N[i].x1>>N[i].y1>>N[i].x2>>N[i].y2;

            N[i].in=i+1;

        }

        for(i=0;i<m;i++)

        {

            bool flag=true;

            cin >> x >> y;

            for(j=n-1; j>=0; j--)

            {

                if(x>=N[j].x1 && x<=N[j].x2 && y>=N[j].y1 && y<=N[j].y2)

                {

                    cout << N[j].in << endl;

                    Node temp = N[j];//位置变化

                    for(k=j+1; k<n; k++)

                    {

                        N[k-1] = N[k];

                    }

                    N[n-1]  =  temp;

                    flag = false;

                    break;

                }

            }

            if(flag) cout << "IGNORED" << endl;

        }

    }

    return 0;

}

遇到的问题和解决方法

位置变换这儿想了好久才知道可以用数组存储解决

心得体会

这道题算简单的了,不过细节处对我来说还是有点难想到。

 

实验名称

实验七 集合竞价

实验内容

某股票交易所请你编写一个程序,根据开盘前客户提交的订单来确定某特定股票的开盘价和开盘成交量。
  该程序的输入由很多行构成,每一行为一条记录,记录可能有以下几种:
  1. buy p s 表示一个购买股票的买单,每手出价为p,购买股数为s
  2. sell p s 表示一个出售股票的卖单,每手出价为p,出售股数为s
  3. cancel i表示撤销第i行的记录。
  如果开盘价为p0,则系统可以将所有出价至少为p0的买单和所有出价至多为p0的卖单进行匹配。因此,此时的开盘成交量为出价至少为p0的买单的总股数和所有出价至多为p0的卖单的总股数之间的较小值。
  你的程序需要确定一个开盘价,使得开盘成交量尽可能地大。如果有多个符合条件的开盘价,你的程序应当输出最高的那一个。

实验要求

输入格式

  输入数据有任意多行,每一行是一条记录。保证输入合法。股数为不超过108的正整数,出价为精确到恰好小数点后两位的正实数,且不超过10000.00。

输出格式

  你需要输出一行,包含两个数,以一个空格分隔。第一个数是开盘价,第二个是此开盘价下的成交量。开盘价需要精确到小数点后恰好两位。

主要仪器设备

台式或笔记本电脑

实验记录(写出实验内容中的程序代码和运行结果)(可分栏或加页)

#include<iostream>

#include<cstdio>

#include<algorithm>

#include<iomanip>

#include<set>

using namespace std;

 

typedef long long ll;

const int MAX = 5007;

struct _Node{

    string m; //buy, sell, cancel

    double p; //出价

    int s;    //股数

    bool e;   //标记第i位的数字是否取消,为true则取消

}r[MAX];      //直接将数组开到最大

set<double> st;

 

int main(){

    int i=0, j=0;

    while(cin >> r[j].m){

        if(r[j].m[0] == 'c'){

            cin >> r[j].s;

            r[r[j].s-1].e = true;

            j++;

            continue;

        }

        cin >> r[j].p >> r[j].s;

        j++;

    }

    for(i=0; i<j; i++)

        if(r[i].m[0] != 'c' && r[i].e==false)

            st.insert(r[i].p);

    ll m_sum = 0;

    double p = 0;

//循环  求出p0的最佳位置

    for(set<double>::iterator it=st.begin(); it!=st.end(); ++it){

        double p0 = *it;

        ll sumb=0, sums=0, sum=0;   //买的总和, 卖的总和,sum取二者最小

 

        for(i=0; i<j; i++)

            if(r[i].m[0] == 's' && !r[i].e && r[i].p<=p0)

                sums += r[i].s;

 

        for(i=0; i<j; ++i)

            if(r[i].m[0] == 'b' && !r[i].e && r[i].p>=p0)

                sumb += r[i].s;

 

        sum = min(sums, sumb);

        if(sum >= m_sum){

            m_sum = sum;

            p = p0;

        }

    }

    cout << fixed << setprecision(2) << p << " " << m_sum << endl;

 

    return 0;

遇到的问题和解决方法

想到用结构体了,但是不是知道该怎么确定最后出价还有就是cancel要如何取消,看了看题解发现出价就在卖家和买家给的假钱上选,取消也要放在结构体里标记。还有就是没想到排序。

心得体会

Set还是蛮好的:自动从小到大排序。用优先队列也可以做,只不过这只需要price

 

实验名称

实验八 游戏

实验内容

  小明在玩一个电脑游戏,游戏在一个n×m的方格图上进行,小明控制的角色开始的时候站在第一行第一列,目标是前往第n行第m列。
  方格图上有一些方格是始终安全的,有一些在一段时间是危险的,如果小明控制的角色到达一个方格的时候方格是危险的,则小明输掉了游戏,如果小明的角色到达了第n行第m列,则小明过关。第一行第一列和第n行第m列永远都是安全的。
  每个单位时间,小明的角色必须向上下左右四个方向相邻的方格中的一个移动一格。
  经过很多次尝试,小明掌握了方格图的安全和危险的规律:每一个方格出现危险的时间一定是连续的。并且,小明还掌握了每个方格在哪段时间是危险的。
  现在,小明想知道,自己最快经过几个时间单位可以达到第n行第m列过关。

实验要求

输入格式

  输入的第一行包含三个整数nmt,用一个空格分隔,表示方格图的行数n、列数m,以及方格图中有危险的方格数量。
  接下来t行,每行4个整数rcab,表示第r行第c列的方格在第a个时刻到第b个时刻之间是危险的,包括ab。游戏开始时的时刻为0。输入数据保证rc不同时为1,而且当rnc不为m。一个方格只有一段时间是危险的(或者说不会出现两行拥有相同的rc)。

输出格式

  输出一个整数,表示小明最快经过几个时间单位可以过关。输入数据保证小明一定可以过关。

主要仪器设备

台式或笔记本电脑

实验记录(写出实验内容中的程序代码和运行结果)(可分栏或加页)

 #include<iostream>

#include<cstdio>

#include<cstring>

#include<algorithm>

#include<cmath>

#include<queue>

using namespace std;

const int N=100+10;

const int M=100+10;

const int T=300+10; //最大可能的时间不可能大于所有的格子数

const int dx[]={0,0,-1,1};//上下走

const int dy[]={-1,1,0,0};//左右走

struct Node

{

    int x,y,t;//x, y 为所在位置,t为时间

    Node(int a,int b,int c)//也可以不写,那么入队则需要q.push((Node)u)

    {

        x=a; y=b; t=c;

    }

};

queue<Node> q;

bool d[N][M][T];

int l[N][M], r[N][M];

int n, m, k;

int bfs()

{

q.push(Node(1, 1, 0));

    d[1][1][0] = true;

while(!q.empty())

    {

        Node u = q.front();

        int ux=u.x, uy=u.y, ut=u.t;

        q.pop();

        for(int i=0; i<4; i++)

        {

            int nx = ux+dx[i], ny = uy+dy[i], nt = u.t+1;

 

            if(nx>n || nx<=0 || ny>m || ny<=0 || d[nx][ny][nt]) continue;//是否越界或搜过

            if(nt<=r[nx][ny] && nt>=l[nx][ny]) continue;//在此时间内不能走动

            if(nx==n && ny==m) return nt;//到达终点,结束

 

            q.push(Node(nx, ny, nt));

            d[nx][ny][nt] = true;

        }

    }

    return 0;

}

int main()

{

int a, b;

scanf("%d%d%d", &n, &m, &k);

 

memset(d, false, sizeof(d));

    memset(l, -1, sizeof(l));

    memset(r, -1, sizeof(r));

    for(int i=0; i<k; i++)

    {

        scanf("%d%d", &a, &b);//位置

        scanf("%d%d", &l[a][b], &r[a][b]);//在l-r时间段内不能走动

    }

    printf("%d\n", bfs());

 

    return 0;

}

遇到的问题和解决方法

刚看这个题的时候不知道该怎么让人不在禁止的时间继续搜索,看了看网上的题解,发现他们用的三维数组,就借鉴别人的写了下。

心得体会

Bfs+queue 这个和模板差不多,稍稍修改下就可以了,所发现的困难就是禁止时间了;该题用三维数组来看是不是可以走还是蛮好玩的。

 

实验名称

实验九 高速公路

实验内容

  某国有n个城市,为了使得城市间的交通更便利,该国国王打算在城市之间修一些高速公路,由于经费限制,国王打算第一阶段先在部分城市之间修一些单向的高速公路。
  现在,大臣们帮国王拟了一个修高速公路的计划。看了计划后,国王发现,有些城市之间可以通过高速公路直接(不经过其他城市)或间接(经过一个或多个其他城市)到达,而有的却不能。如果城市A可以通过高速公路到达城市B,而且城市B也可以通过高速公路到达城市A,则这两个城市被称为便利城市对。
  国王想知道,在大臣们给他的计划中,有多少个便利城市对。

实验要求

输入格式

  输入的第一行包含两个整数nm,分别表示城市和单向高速公路的数量。
  接下来m行,每行两个整数ab,表示城市a有一条单向的高速公路连向城市b

输出格式

  输出一行,包含一个整数,表示便利城市对的数量。

样例输入

5 5
1 2
2 3
3 4
4 2
3 5

样例输出

3

主要仪器设备

台式或笔记本电脑

实验记录(写出实验内容中的程序代码和运行结果)(可分栏或加页)

#include<iostream>

using namespace std;

#include<cstring>

#include<algorithm>

int n,m;

int head[10010],stack[10010],DFN[10010],Low[10010];

int Belong[10010],instack[10010],cnt,top,f,scnt;

struct Node

{

    int e,next;

}edge[100010];

void add(int s,int e)

{

    edge[f].e=e;

    edge[f].next=head[s];

    head[s]=f++;//链式前向星

}

void tarjan(int s)

{

    int t,k,i;

    DFN[s]=Low[s]=++cnt;

    stack[top++]=s;//模拟栈,也可直接用栈push

    instack[s]=1;//用来判断是否在栈里

for(i=head[s];i!=-1;i=edge[i].next)

    {

        k=edge[i].e;//

        if(!DFN[k])

        {

            tarjan(k);

            Low[s]=min(Low[k],Low[s]);

        }

        else if(instack[k])

        {

            Low[s]=min(Low[s],DFN[k]);

        }

    }

    if(Low[s]==DFN[s])//根结点

    {

        scnt++;

        do

        {

            t=stack[--top];

            Belong[t]=scnt;//所属第几个强联通分量

            instack[t]=0;

        }

        while(s!=t);

    }

}

int main()

{

    int i,j,a,b,v[10010];

    cin>>n>>m;

    f=1;

memset(head,-1,sizeof(head));

    memset(v,0,sizeof(v));

memset(edge, 0, sizeof(edge));

for(i=0;i<m;i++)

    {

        cin>>a>>b;

        add(a,b);//也可选择用向量数组存储

    }

 

    memset(DFN,0,sizeof(DFN));

 

    for(i=1;i<=n;i++)

    {

        if(!DFN[i])

            tarjan(i);

}

for(i=1;i<=n;i++)

        v[Belong[i]]++;//每个城市所在的强联通分量连接了多少条边

long long sum=0;

for(i=0;i<=n;i++)

    {

        if(v[i]>1)    sum=sum+v[i]*(v[i]-1)/2;//C(n, 2

    }

    cout<<sum<<endl;

    return 0;

}

遇到的问题和解决方法

必须清空该结构体或向量数组,也必须清空,否则当测试数据递减时 WA

公式可简化为C(2n)=n(n1)/2。用dfs会运行超时

心得体会

学了一点tarjan,也了解了邻接表,就是运用起来还有点困难。这道题相当于强联通的模板题了,直接套进去就好了。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值