gougou40 (1)

  开始做狗狗40题,不知道在毕业前能不能做完。

  第一题The Willy Memorial Program就虐死我了,恶心的模拟……

  数据范围超小,于是开始乱搞……我的思路是用水将能填满的水管都填满,填满的步骤是根据水位来进行的(每升高单位水位算一个步骤),于是每个步骤可以分为以下几个小步骤:1~判断当前共有几个水管是一起升高水位的(程序中用n表示),那个该步骤就加入n个单位水位,使得这些水管中每个水管的水位上升一单位;2~判断当前有无可能达到目标水位线;3~若达到目标水位线,判断是否已溢出(虽然在程序中认为水管有盖,但是题目中水管是没有盖的,所以要加入这个判断,这个判断比较简单,写个循环判断水位线是否达到了已存在的水管中y值在最低——或者说y值在最大——位置的水管盖子),若没有则进入下一步。最后,若所有水管已填满但还没有达到指定水位线则算溢出情况。

  因为实际目标比实际目标水位线稍微高一点,如果到达水位线后直接进行判断有点繁琐(考虑到连接其他的水管,题目中也已提到),所以我用这一步的下一步进行判断,下一步若淹过目标水位线,则前一步就是答案,只需要这一步的总体积减去这一步所用的体积(程序中的v-n)即为答案。

  当然,之前需要先预处理一下水管之间的连接情况(储存在程序中的pc)。在判断连接水管时用vector储存(我是用vector来实现BFS的)。

  注意:有数据是指定水位线并不在水管内部(尤其是在水管下方,已经超出水管范围的位置,这里我WA了不知道多多少次才发现)。

  参考程序如下。

#include <vector>

#include <list>

#include <map>

#include <set>

#include <deque>

#include <queue>

#include <stack>

#include <bitset>

#include <algorithm>

#include <functional>

#include <numeric>

#include <utility>

#include <sstream>

#include <iostream>

#include <iomanip>

#include <cstdio>

#include <cmath>

#include <cstdlib>

#include <cctype>

#include <string>

#include <cstring>

#include <ctime>

#include <fstream>

using namespace std;

int t, p, px[20], py[20], height[20], l, lx, ly, length, target, level, mat[20], w[20];

vector<int> myvector;

struct

{

    int n, to[50], pos[50];

}pc[20];

int present(int *mat)

{

    int n = 0, wlevel = 0;

    for(int i = 0; i < myvector.size(); i++)

    {

        int m = myvector[i];

        for(int j = 0; j < pc[m].n; j++)

        {

            if(py[m] + height[m] - w[m] <= pc[m].pos[j] && find(myvector.begin(), myvector.end(), pc[m].to[j]) == myvector.end())

                myvector.push_back(pc[m].to[j]);

        }

    }

    int sz = myvector.size();

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

    {

        int m = myvector[i];

        if(w[m] < height[m] && py[m] + height[m] - w[m] > wlevel)

        {

            n = 0;

            mat[n++] = m;

            wlevel = py[m] + height[m] - w[m];

        }

        else if(w[m] < height[m] && py[m] + height[m] - w[m] == wlevel)

            mat[n++] = m;

    }

    return n;

}

bool boiled()

{

    if(w[target] + level > py[target] + height[target])

        return 1;

    return 0;

}

bool filled()

{

    int mx = 0;

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

        if(w[i])

            mx = max(mx, py[i]);

    if(level <= mx)

        return 1;

    return 0;

}

int main()

{

    cin >> t;

    while(t--)

    {

        cin >> p;

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

            cin >> px[i] >> py[i] >> height[i];

        memset(pc, 0, sizeof(pc));

        cin >> l;

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

        {

            cin >> lx >> ly >> length;

            for(int j = 0; j < p; j++)

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

                    if((px[j] + 1 == lx && px[k] == lx + length) || (px[j] == lx + length && px[k] + 1== lx))

                    {

                        pc[j].to[pc[j].n] = k;

                        pc[j].pos[pc[j].n] = ly;

                        pc[j].n++;

                    }

        }

        cin >> target >> level;

        target--;

        memset(w, 0, sizeof(w));

        myvector.clear();

        myvector.push_back(0);

        int v = 0, n = 0;

        bool b = 1;

        while(v <= 400)

        {

            n = present(mat);

            if(!n)

            {

                b = 0;

                break;

            }

            v += n;

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

                w[mat[i]]++;

            if(boiled())

                break;

        }

        if(b && level <= py[target] + height[target] && !filled())

            cout << v - n << endl;

        else

            cout << "No Solution" << endl;

    }

    return 0;

}

  第二题Farmland搞定。

  我的思路是去找逆时针旋转,定下某个顶点时,角度改变最大的那个点(第三个点),这里共涉及两条边,还未超过该点时的一条边(该点与该点之前的点组成的边),以及超过该点时的一条边(该点与该点之后的点组成的边),以该点位旋转点时,前一条边经过最大的角度(逆时针旋转)达到另一条边。按照这个思路,当完成点与点相邻情况的储存后(邻接表),定下前两个点(该点前一个点和该点)就可以确定第三个点(该点之后的点),以上“该点”在程序中设为o点(因为两条边是通过该点旋转的,有中心的意思),接着设该o点之前点为m点,那么可以唯一确定第三个点设为n点,于是用一个next函数储存,即next[m][o]=n(m与o不相邻时,next值为-1)。

  实际上以上的程序还有一个问题,这是在我一开始没有想到的,也为此WA了很多次,就是这样用next函数确定多边形,有两种情况:一种是题目所要求的多边形(内部没有杂点杂边,不然在题设图是connected的情况下,选择点和边时会选中里面的点和边,原因就是选择这些点和边会比外面的点和边旋转角度更大),此时,这个多边形是正方向的(对于内部来说),且是逆时针的;另一种则是当整个图的外部没有杂点和杂边的时候,有可能会产生这个图的最外部的多边形(实际上,若把无穷大点也作为一个有意义的点的时候,这种多边形也是满足题意的,因为这个多边形的方向对于外部区域来说是正方向的,虽然它本身是顺时针的,此时这个多边形的内部就是整个图的外部,这种思想在复变函数中很常见,比如求一个复变函数的回路积分的时候,当这个复变函数只有有限个孤立奇点,且孤立奇点都在回路内部,那么就可以用无穷大点——也是一个孤立奇点——的留数来计算,此时的正方向就是顺时针而非逆时针)。解决的方法是多一个多边形是逆时针还是顺时针的判断:在平面中任取一点(一般为原点),按照点的顺序,求每两个相邻的点的cross product(严格地来说,是这两点与原点组成的两个向量的cross product),想加后求出来的是这个多边形的面积(的两倍),当然,这个面积是带方向的,正为逆时针,负为顺时针,证明略麻烦,以后有时间了再把严格的证明放上来。

  具体在实施,判断旋转角度的时候我用的是cross product和inner product共同判断的方法(前者主要判断正负来决定位置,后者在决定了位置后决定其角度的大小,注意前者因为只需要正负所以不需要单位化,但后者需要用大小所以需要单位化处理,这里我也WA了几次)。 

  另外,求出的答案需要除以size,因为从满足条件的多边形上的每个点出发都可以得到同一多边形。

  具体的代码如下。

#include <vector>

#include <list>

#include <map>

#include <set>

#include <deque>

#include <queue>

#include <stack>

#include <bitset>

#include <algorithm>

#include <functional>

#include <numeric>

#include <utility>

#include <sstream>

#include <iostream>

#include <iomanip>

#include <cstdio>

#include <cmath>

#include <cstdlib>

#include <cctype>

#include <string>

#include <cstring>

#include <ctime>

#include <fstream>

using namespace std;

double dist(int x, int y)

{

    return sqrt(double(x * x + y * y));

}

double InnerProduct(int xa, int ya, int xb, int yb)

{

    double d = dist(xb, yb);

    return xa * (xb / d) + ya * (yb / d);

}

int CrossProduct(int xa, int ya, int xb, int yb)

{

    return xa * yb - ya * xb;

}

int main()

{

    int M, N, v[200], rv[200], x[200], y[200], d[200], sd, ad[200][200], next[200][200], sz, mat[201], sum;

    vector<int> myvector;

    cin >> M;

    while(M--)

    {

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

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

        sd = sum = 0;

        cin >> N;

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

        {

            cin >> v[i];

            rv[v[i]] = i;

            cin >> x[v[i]] >> y[v[i]] >> d[v[i]];

            sd += d[v[i]];

            for(int j = 0; j < d[v[i]]; j++)

                cin >> ad[v[i]][j];

        }

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

        {

            int o = v[i];

            for(int j = 0; j < d[o]; j++)

            {

                int m = ad[o][j], index = ad[o][0];

                for(int k = 1; k < d[o]; k++)

                {

                    if(m == ad[o][k])

                        continue;

                    if(m == index)

                    {

                        index = ad[o][k];

                        continue;

                    }

                    int n = ad[o][k];

                    int OMcpON = CrossProduct(x[m] - x[o], y[m] - y[o], x[n] - x[o], y[n] - y[o]);

                    int OMcpOI = CrossProduct(x[m] - x[o], y[m] - y[o], x[index] - x[o], y[index] - y[o]);

                    if(OMcpON)

                    {

                        if(OMcpON > 0 && OMcpOI > 0)

                        {

                            double OMipON = InnerProduct(x[m] - x[o], y[m] - y[o], x[n] - x[o], y[n] - y[o]);

                            double OMipOI = InnerProduct(x[m] - x[o], y[m] - y[o], x[index] - x[o], y[index] - y[o]);

                            if(OMipON < OMipOI)

                                index = n;

                        }

                        if(OMcpON < 0)

                        {

                            if(OMcpOI >= 0)

                                index = n;

                            else

                            {

                                double OMipON = InnerProduct(x[m] - x[o], y[m] - y[o], x[n] - x[o], y[n] - y[o]);

                                double OMipOI = InnerProduct(x[m] - x[o], y[m] - y[o], x[index] - x[o], y[index] - y[o]);

                                if(OMipON > OMipOI)

                                    index = n;

                            }

                        }

                    }

                    else if(OMcpOI > 0)

                        index = n;

                }

                next[m][o] = index;

            }

        }

/*check the next function

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

            for(int j = 0; j < 200; j++)

                if(next[i][j] != -1)

                    cout << i << ' ' << j << ' ' << next[i][j] << endl;

*/

        cin >> sz;

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

        {

            int o = v[i];

            for(int j = 0; j < d[o]; j++)

            {

                int tmpsz = sz - 2;

                myvector.clear();

                myvector.push_back(o);

                int pre = o, no = ad[o][j];

                if(find(myvector.begin(), myvector.end(), no) == myvector.end())

                    myvector.push_back(no);

                int post = no;

                while(tmpsz--)

                {

                    int tmp = next[pre][post];

                    if(tmp == -1)

                        break;

                    if(find(myvector.begin(), myvector.end(), tmp) == myvector.end())

                        myvector.push_back(tmp);

                    pre = post;

                    post = tmp;

                }

                if(myvector.size() == sz && next[pre][post] == o && next[post][o] == no)

                {

                    tmpsz = 0;

                    for(vector<int>::iterator it = myvector.begin(); it != myvector.end(); it++)

                        mat[tmpsz++] = *it;

                    mat[tmpsz] = *myvector.begin();

                    int area = 0;

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

                    {

                        //cout << mat[k] << ' ' << mat[k + 1] << endl;

                        area += CrossProduct(x[mat[k]], y[mat[k]], x[mat[k + 1]], y[mat[k + 1]]);

                    }

                    //cout << area << endl;

                    if(area > 0)

                        sum++;

                }

            }

        }

        //cout << sum << endl;

        cout << sum / sz << endl;

    }

    return 0;

}

   第三题Transmitters搞定!

  1A搞定,这题原来我两年前做过,当时用的还是C,估计是为了凑齐当时选入集训队的99分……这题比起上两题来说不知道要人性化多少,用一个cross product判断以r为中心的两个点(有顺序)的逆时针角度是否超过pi就行,复杂度O(n^2)即可过(n=150的数据量实在是很小,0msAC)。

#include <vector>

#include <list>

#include <map>

#include <set>

#include <deque>

#include <queue>

#include <stack>

#include <bitset>

#include <algorithm>

#include <functional>

#include <numeric>

#include <utility>

#include <sstream>

#include <iostream>

#include <iomanip>

#include <cstdio>

#include <cmath>

#include <cstdlib>

#include <cctype>

#include <string>

#include <cstring>

#include <ctime>

#include <fstream>

using namespace std;

int dist(int rx, int ry, int x, int y)

{

    return (x - rx) * (x - rx) + (y - ry) * (y - ry);

}

int CrossProduct(int xi, int yi, int xj, int yj)

{

    return xi * yj - yi * xj;

}

int main()

{

    int rx, ry;

    double r;

    while(cin >> rx >> ry >> r)

    {

        if(r < 0)

            break;

        r = r * r;

        int N, x[150], y[150], k = 0;

        cin >> N;

        for(int i = 0, _x, _y; i < N; i++)

        {

            cin >> _x >> _y;

            if(dist(rx, ry, _x, _y) <= r)

            {

                x[k] = _x;

                y[k] = _y;

                k++;

            }

        }

        int mx = 0;

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

        {

            int cnt = 0;

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

                if(CrossProduct(x[i] - rx, y[i] - ry, x[j] - rx, y[j] - ry) >= 0)

                    cnt++;

            mx = max(mx, cnt);

        }

        cout << mx << endl;

    }

    return 0;

}

  结束了答辩(好吧,我貌似还要二辩),继续gougou40的节奏。

  Split Windows是一道巨恶心的模拟题(虽然目测后面还有更多更恶心的模拟题),本来打算用链表写树,后来觉得没这个必要,还是用数组写了。

  我的思路用了两次递归,第一次是计算总window的width&height,第二次是根据父节点的width&height推子节点的width&height,同时画出此split时window的形状。一开始觉得好难画,后来想了一下,递归的时候把某时刻的LRUD(左右上下,也就是子window的框架)全部记录,并递归下去的话,还是比较容易画的。具体画法是:首先画出window的轮廓(初始化),每分割一次就画分割线(注意当'-'和'|'遇到时要变成'*'),最后递归到字母时,直接在左上角将本来的字符用字母覆盖即可。

  数据应该不是太强,而且样例也给的也应该是数据里面比较强的了,所以只要能写出一般就不会WA(不过因为一开始window的初始化错误,我还是WA了3次,太弱了……)。

#include <vector>

#include <list>

#include <map>

#include <set>

#include <deque>

#include <queue>

#include <stack>

#include <bitset>

#include <algorithm>

#include <functional>

#include <numeric>

#include <utility>

#include <sstream>

#include <iostream>

#include <iomanip>

#include <cstdio>

#include <cmath>

#include <cstdlib>

#include <cctype>

#include <string>

#include <cstring>

#include <ctime>

#include <fstream>

using namespace std;

const long double pi = 3.1415926535898;

#define maxw 1024

#define maxn 128

char window[maxw][maxw];

struct T

{

    char label;

    int parent, left, right, width, height;

}Tree[maxn];

void calculate(int root)

{

    if(isupper(Tree[root].label))

        return;

    int left = Tree[root].left, right = Tree[root].right;

    calculate(left);

    calculate(right);

    if(Tree[root].label == '-')

    {

        Tree[root].width = max(Tree[left].width, Tree[right].width);

        Tree[root].height = Tree[left].height + Tree[right].height;

    }

    if(Tree[root].label == '|')

    {

        Tree[root].height = max(Tree[left].height, Tree[right].height);

        Tree[root].width = Tree[left].width + Tree[right].width;

    }

}

void stretch(int root, int L, int R, int U, int D)

{

    if(isupper(Tree[root].label))

    {

        window[U][L] = Tree[root].label;

        return;

    }

    int left = Tree[root].left, right = Tree[root].right;

    if(Tree[root].label == '-')

    {

        Tree[left].width = Tree[right].width = Tree[root].width;

        int sheight = Tree[left].height + Tree[right].height;

        Tree[left].height = Tree[root].height * Tree[left].height / sheight + (Tree[root].height * Tree[left].height % sheight != 0);

        Tree[right].height = Tree[root].height - Tree[left].height;

        int h = U + Tree[left].height;

        for(int i = L; i <= R; i++)

            if(window[h][i] == ' ')

                window[h][i] = '-';

            else if(window[h][i] == '|')

                window[h][i] = '*';

    }

    if(Tree[root].label == '|')

    {

        int swidth = Tree[left].width + Tree[right].width;

        Tree[left].width = Tree[root].width * Tree[left].width / swidth + (Tree[root].width * Tree[left].width % swidth != 0);

        Tree[right].width = Tree[root].width - Tree[left].width;

        Tree[left].height = Tree[right].height = Tree[root].height;

        int w = L + Tree[left].width;

        for(int i = U; i <= D; i++)

            if(window[i][w] == ' ')

                window[i][w] = '|';

            else if(window[i][w] == '-')

                window[i][w] = '*';

    }

    stretch(left, L, L + Tree[left].width, U, U + Tree[left].height);

    stretch(right, R - Tree[right].width, R, D - Tree[right].height, D);

}

int main()

{

    int N, n = 1;

    cin >> N;

    while(N--)

    {

        string str;

        cin >> str;

        int sz = str.size(), parent = 0;

        Tree[0].parent = Tree[0].left = Tree[0].right = -1;

        if(isupper(Tree[0].label = str[0]))

            Tree[0].width = Tree[0].height = 2;

        else

            Tree[0].width = Tree[0].height = 0;

        for(int i = 1; i < sz; i++)

        {

            Tree[i].parent = parent;

            Tree[i].left = Tree[i].right = -1;

            if(Tree[parent].left == -1)

                Tree[parent].left = i;

            else

                Tree[parent].right = i;

            if(isupper(Tree[i].label = str[i]))

            {

                while(parent >= 0 && Tree[parent].right >= 0)

                    parent = Tree[parent].parent;

                Tree[i].width = Tree[i].height = 2;

            }

            else

            {

                parent = i;

                Tree[i].width = Tree[i].height = 0;

            }

        }

/*check the Tree

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

            cout << Tree[i].label << ' ' << Tree[i].parent << ' ' << Tree[i].left << ' ' << Tree[i].right << endl;

*/

        calculate(0);

        //cout << Tree[0].width << ' ' << Tree[0].height << endl;//check the width and height of the window

        for(int i = 0; i <= Tree[0].height; i++)

        {

            for(int j = 0; j <= Tree[0].width; j++)

                if((i == 0 || i == Tree[0].height) && (j == 0 || j == Tree[0].width))

                    window[i][j] = '*';

                else if(i == 0 || i == Tree[0].height)

                    window[i][j] = '-';

                else if(j == 0 || j == Tree[0].width)

                    window[i][j] = '|';

                else

                    window[i][j] = ' ';//initialize the window

            window[i][Tree[0].width + 1] = 0;

        }

        stretch(0, 0, Tree[0].width, 0, Tree[0].height);

/*check the width and height of the window splits

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

            cout << Tree[i].label << ' ' << Tree[i].width << ' ' << Tree[i].height << endl;

*/

        cout << n++ << endl;

        for(int i = 0; i <= Tree[0].height; i++)

            puts(window[i]);

    }

    return 0;

}

  gougou第一部分结束(打算每部分4题,也不知道自己能坚持几个部分……)。

你可能感兴趣的:(Go)