hdu 2013 ACM/ICPC Asia Regional Online —— Warmup解题报告

即hdu题库中的4706-4715


4706 - Children's Day

题意:用a~z构造一个反"N"型图形,z后面接a;

思路:直接cout构造就可以了,大水题,不过可以写写循环练习代码能力


代码:

#include "iostream"
#include "cstring"
#include "algorithm"
#include "cmath"
#include "cstdio"
#include "sstream"
#include "queue"
#include "vector"
#include "string"
#include "stack"
#include "cstdlib"
#include "deque"
#include "fstream"
#include "map"
using namespace std;
typedef long long LL;
const int INF = 0x1fffffff;
const int MAXN = 1000;

char mir[] = "abcdefghijklmnopqrstuvwxyz";
int cnt=0;

char out[11][11];

void mk(int n)
{
    for(int i = 0 ; i < 10 ; i++)
        fill(out[i],out[i]+10,' ');

    for(int i = 0 ; i < n ; i++)
    {
        out[i][0] = mir[(cnt+i)%26];
        out[i][n-1] = mir[(cnt+i+2*n-2)%26];
        out[i][n-1-i] = mir[(cnt-i+2*n-2)%26];
        out[i][n] = '\0';
    }

    cnt+=3*n-2;

    for(int i = 0 ; i < n ; i++)
        cout << out[i] << endl;
}

int main()
{
    for(int i = 3 ; i<=10 ;i++)
        mk(i);

    return 0;
}

4707 - Pet

题意:0点有个探测器,能探测到距0点D单位以内的仓鼠,输入x,y表示x在y旁边,也就是说x与y相差一个单位,每一个点可达到0点,问仓鼠有可能在哪几个地方,输出个数

思路:其实就是构造一颗树,以0为根节点,每条边权都为1,求子节点到根节点权值超过D的点的个数,一个简单的简化拓扑排序


代码:

#include "iostream"
#include "cstring"
#include "algorithm"
#include "cmath"
#include "cstdio"
#include "sstream"
#include "queue"
#include "vector"
#include "string"
#include "stack"
#include "cstdlib"
#include "deque"
#include "fstream"
#include "map"
using namespace std;
typedef long long LL;
const int INF = 0x1fffffff;
const int MAXN = 1000;

int in[100010];

int main()
{
    int t;
    cin >> t;

    while(t--)
    {
        memset(in,0,sizeof(in));
       int n,d;
       cin >> n >> d;
       for(int i=1 ; i < n ; i++)
       {
           int x,y;
           scanf("%d%d",&x,&y);
           in[y] = in[x]+1;
       }

       int cnt=0;
       for(int i=0 ; i < n ; i++)
            if(in[i] > d)
                cnt++;

        cout << cnt << endl;
    }

    return 0;
}


4708 - Rotation Lock Puzzle

题意:每一圈(条纹走向相等的为一圈)可以顺逆时针旋转,求的是旋转后每一圈四个角的和+最中间数的和(即整体矩形的两条对角线元素的和,中间那个算一次),以及最小旋转次数

思路:已知的是:(仅考虑在某一圈)如果两个数能够在旋转后居于对角角落位置,则有(x1,y1)+(x2,y2)=(n+1,n+1) ; 如果两个数能够在旋转后居于非对角角落位置(在矩形的同一条边上) , 则有x1=y2 , x2+y1 = n+1; 这样,我们只要枚举一条边的一个点就可以了

特别注意:当遇到maxc相等的时候,别忘了更新最小旋转次数!!


代码:

#include "iostream"
#include "cstring"
#include "algorithm"
#include "cmath"
#include "cstdio"
#include "sstream"
#include "queue"
#include "vector"
#include "string"
#include "stack"
#include "cstdlib"
#include "deque"
#include "fstream"
#include "map"
using namespace std;
typedef long long LL;
const int INF = 0x1fffffff;
const int MAXN = 1000;

int cir[20][20];

int main()
{
    int n;
    while(cin >> n && n)
    {
        for(int i = 1 ; i<= n ; i++)
            for(int j = 1 ; j <= n ; j++)
                cin >> cir[i][j];

        int res1=0,res2=0;
        for(int i = 1 ; i <= n/2;i++)
        {
            int maxc = -1000000,pos=0;
            for(int j = i ; j <= n-i ; j++)
            {
                int res = cir[i][j] +cir[j][n-i+1] + cir[n+1-j][i] + cir[n+1-i][n+1-j];
                if(maxc < res)
                {
                    maxc = res;
                    pos = min(j-i,n-i-j+1);
                }
                else if(maxc == res)
                    pos = min(pos,min(j-i,n-i-j+1));
            }
            res1 += maxc;
            res2 += pos;
        }

        cout << res1+cir[n/2+1][n/2+1] << ' ' << res2 << endl;
    }

    return 0;
}



4709 - Herding

题意:给一组点,求能构成的三角形的最小面积

思路:才100个点,三个for循环直接暴力枚举,这里麻烦的是三角形面积,用海伦公式太不靠谱,介绍用叉乘计算:


三角形面积计算法 : 给定三个顶点 , 两两相减得到两条边向量A,B ; 则 S = |A × B /2| , 又 A × B = |  i    j   | = (x1*y2) i- (x2*y1)j ;  所以 S = |((x1*y2) - (x2*y1))/2 |;

                                                                                                                                                      | x1 y1 |

                                                                                                                                                      | x2 y2 |


代码:

#include "iostream"
#include "cstring"
#include "algorithm"
#include "cmath"
#include "cstdio"
#include "sstream"
#include "queue"
#include "vector"
#include "string"
#include "stack"
#include "cstdlib"
#include "deque"
#include "fstream"
#include "map"
using namespace std;
typedef long long LL;
const int INF = 0x1fffffff;
const int MAXN = 1000000+10;

struct node
{
    double x,y;

    node(double tx=0 , double ty = 0)
    {
        x = tx;
        y = ty;
    }

    node operator - (const node&b)const
    {
        return node(x-b.x,y-b.y);
    }

    double operator *(const node&b)const
    {
        return x*b.y-y*b.x;
    }
}p[110];

int main()
{
    int t;
    cin >> t;

    while(t--)
    {
        int n;
        cin >> n;

        for(int i = 0 ; i < n ; i++)
            cin >> p[i].x >> p[i].y;

        double minc = INF;
        for(int i = 0 ; i < n ; i++)
            for(int j = i+1 ; j < n ; j++)
                for(int k = j+1 ; k < n ; k++)
                {
                    double area = fabs(((p[i]-p[k])*(p[i]-p[j]))/2.0);
                    if(area < 1e-10)
                        continue;
                    minc = min(minc,area);
                }

        if(minc == INF)
            cout << "Impossible" << endl;
        else
            printf("%.2lf\n",minc);
    }

    return 0;
}


4710 - Balls Rearrangement


4711 - Weather


4712 - Hamming Distance

题意:给N个长度为5的16进制数,两两之间求异或并记录结果中1的个数,输出最小个数

思路:基本知识:十六进制的每一位可以转化成对应10进制数的四位二进制,如A = 10 = 1010等。这样我们可以进行这样一个预处理:记cmp[i][j]是i和j异或结果中1的个数,这样对于每一组,我们只需for(i,0,5)枚举每一位就可以了。但本题难点是数据量有100000,实在太大,就在这卡了好久………………结果网上搜解题报告,搜出来却是用随机数来定位…………当时心中一万个草泥马啊!!!果然小菜鸟阅历还是太少了。然后设定随机50W次后就华丽滴过了。。。。


代码:

#include "iostream"
#include "cstring"
#include "algorithm"
#include "cmath"
#include "cstdio"
#include "sstream"
#include "queue"
#include "vector"
#include "string"
#include "stack"
#include "cstdlib"
#include "deque"
#include "fstream"
#include "map"
using namespace std;
typedef long long LL;
const int INF = 0x1fffffff;
const int MAXN = 500000;

int cmp[16][16];
string hm[100000+10];

void mkCmp()
{
    for(int i = 0 ; i < 16 ; i++)
        for(int j = i ; j < 16 ; j++)
        {
            int tmp = i^j,cnt=0;
            for(int k = 0 ; k < 4 ; k++)
                if((1<<k) & tmp)
                    cnt++;
            cmp[i][j] = cmp[j][i] = cnt;
        }
}

int change(char a)
{
    if(isalpha(a))
        return a-'A'+10;
    return a-'0';
}

int calc(int a , int b)
{
    int ans=0;

    for(int i = 0 ; i < 5 ; i++)
    {
        int x = change(hm[a][i]);
        int y = change(hm[b][i]);

        ans += cmp[x][y];
    }

    return ans;
}


int main()
{
    mkCmp();
    int t;
    cin >>t;

    while(t--)
    {
        int n;
        cin >> n;

        for(int i = 0 ; i < n ; i++)
            cin >> hm[i];

        int minc = INF;
        for(int i = 0 ; i < MAXN ; i++)
        {
            int a = rand()%n;
            int b = rand()%n;
            if(a == b) b = (b+1)%n;

            minc = min(minc,calc(a,b));
        }

        cout << minc << endl;
    }

    return 0;
}



4713 - Permutation


4714 - Tree2cycle

题意:给一棵树,要求最少 (剪掉几根边+加上几根边) 能形成一个环(环的定义是无分支的环链,即每个点的度是2)

思路:先通到树的最深处,然后往上处理,遇到度>=2的就减到二为止,根节点1减到1,这样每个点都是散的,当然有减就有加,剪一条边意味着最后一定会将这个边接到别的点上,再加上最后根节点与尾结点相连成环,最后需要(剪的边数*2+1)次操作,即答案,算贪心思想吧,证明无力。。。。。


注意:dfs用默认栈的话会爆,用"#pragma comment(linker, "/STACK:102400000,102400000")"自己创建更大的栈,新技能get√


代码:

是分析某位大神的代码写出来的,本人有想法但写不出来,智商捉急

#pragma comment(linker, "/STACK:102400000,102400000")
#include "iostream"
#include "cstring"
#include "algorithm"
#include "cmath"
#include "cstdio"
#include "sstream"
#include "queue"
#include "vector"
#include "string"
#include "stack"
#include "cstdlib"
#include "deque"
#include "fstream"
#include "map"
using namespace std;
typedef long long LL;
const int INF = 0x1fffffff;
const int MAXN = 1000000+100;

vector<int> G[MAXN];
int res;

bool dfs(int cur , int fa)
{
    int cnt=0;

    for(int i = 0 ; i < G[cur].size() ; i++)    //记下在疯狂的剪边之后还有哪些点赖在父亲身上
    {
        int next = G[cur][i];

        if(fa == next) continue;            //如果是前驱就略过

        if(dfs(next,cur))
            cnt++;
    }

    if(cnt >= 2)
    {
        if(cur == 1)        //注意剪的首先是父节点相连的那条边,否则算法不成立
            res += cnt-2;
        else
            res += cnt-1;

        return false;       //父子边剪掉了,就不用计数了
    }

    return true;
}

int main()
{
    int t;
    scanf("%d",&t);

    while(t--)
    {

        int n;
        scanf("%d",&n);

        for(int i = 0 ; i <= n ;i++)
            G[i].clear();



        for(int i = 1 ; i < n ; i++ )
        {
            int a,b;
            scanf("%d%d",&a,&b);

            G[a].push_back(b);          //不能确定谁是谁的前驱,所以索性构造双向边,深搜时不必担心无限循环,vector邻接表还需掌握
            G[b].push_back(a);
        }

        res = 0;
        dfs(1,-1);

        printf("%d\n",res*2+1);
    }

    return 0;
}



4715 - Difference Between Primes

题意:输入一个数,输出两个素数,这两个素数a,b满足a-b == n ,且a是最小的

思路:构造素数表是一定的,用筛法,然后从小到大枚举比n大的素数,只要满足a-n是素数就可以了,水题


代码:

#include "iostream"
#include "cstring"
#include "algorithm"
#include "cmath"
#include "cstdio"
#include "sstream"
#include "queue"
#include "vector"
#include "string"
#include "stack"
#include "cstdlib"
#include "deque"
#include "fstream"
#include "map"
using namespace std;
typedef long long LL;
const int INF = 0x1fffffff;
const int MAXN = 1000000+10;

int tp[MAXN];
vector<int> prime;
int n;

void init()
{
    tp[0]=tp[1]=1;
    for(int i = 2 ;i < MAXN ; i++)
        if(!tp[i])
            for(int j = i+i ; j < MAXN ; j+=i)
                tp[j] = 1;

    for(int i = 0 ; i < MAXN ; i++)
        if(!tp[i])
            prime.push_back(i);
}

int main()
{
    int t;
    cin >>t;
    init();

    while(t--)
    {
        cin >> n;

        int ok = 0;

        for(int i = 0 ; i < prime.size() ; i++)
            if(prime[i] > n && !tp[prime[i]-n])
            {
                ok = 1;
                cout << prime[i] << ' ' << prime[i]-n << endl;
                break;
            }

        if(!ok)
            cout << "FAIL" << endl;
    }

    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值