zoukankan      html  css  js  c++  java
  • ZOJ 3879 Capture the Flag

    以此题纪念我写的第一篇acm博客,第一道模拟:)

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3879

    题意非常复杂,感觉好像在写一个游戏似的,一大堆规则,还全部都是纯模拟,一点算法都没有,全考代码的……

    废话结束,开始说题——

      第一行输入t,表示有t组数据

      每组数据,第一行输入n, q, s, c,表示有n组队伍,每队q个地点,每队初始s分,一共c次操作

      接下来c组操作……

      每组操作,第一行输入m, 表示m次成功攻击

      接下来m次攻击……每次输入a, b, c,表示a攻击b的c地点。

      接下来输入q行,每行n个数,表示每队伍的每个地点的状态,1表示好,0表示不好……

      接下来一行输入d,表示d次查询

      接下来一行输入d个数,表示查询d组队的得分情况,并查询这几组队的排名……

    规则:

      攻击n组队,每队q个地点。

      每一回合(即每次操作):

        如果第a队共有b个地点被攻击,无论多少队伍攻击他,每个地点十七失去(n-1)分,一共失去b*(n-1)分。攻击那个地点的队伍平均获得那个地点失去的(n-1)分。

        如果第a队的c地点状态为“不好”,则a队失去(n-1)分.

        如果第a队的c地点状态为“好”,c地点状态不好的队伍的个数为k,则a队获得(n-1)*k/(n-k);

        如果两支队伍的得分之差<0.00001,则认为两支队伍排名相同……

    (坑死爹的规则啊啊啊啊啊啊)

    写这道题要注意——

      1. 判断那个0.00001

      2. 如果在同一回合,a队攻击了b队的c地点多次,则只认为他攻击了一次

      3. 下一回合各个地点的状态重置……

    ps.写完发现……

      1.  其实这道题我的姿势很挫,但最终还是过了……谢天谢地……

      2.  题很水,我也很水

    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    
    using namespace std;
    
    const int N = 110;
    const int NN = 20;
    
    struct node                     //存各支队伍的信息
    {
        bool q[NN];                 //个地点的状态
        double point;               //得分
        bool ed[NN][N];             //c点是否被b队攻击
        bool edp[NN];               //c点是否被攻击
        int eds[NN];                //c点被攻击了几次
    }tm[N];
    
    struct node1                    //按得分排序使用,这是最搓的地方……
    {
        int flag;
        double p;
        int r;
    }sorting[N];        
    
    int t;
    int n, q, c;
    double s;
    int sum[NN];                                    //存c地点良好状态的队伍数
    
    bool cmp(node1 x, node1 y)
    {
        return x.p - y.p > 0.00001;                 //坑爹的0.00001
    }
    
    void update()                                   //数据初始化
    {
        for(int i = 0; i < n; i++)
        {
            memset(tm[i].q, 0, sizeof(tm[i].q));
            memset(tm[i].ed, 0, sizeof(tm[i].ed));
            memset(tm[i].edp, 0, sizeof(tm[i].edp));
            memset(tm[i].eds, 0, sizeof(tm[i].eds));
        }
        memset(sum, 0,sizeof(sum));
    }
    
    int main()
    {
        //freopen("test.txt", "r", stdin);
        scanf("%d", &t);
        while(t--)
        {
            scanf("%d%d%lf%d", &n, &q, &s, &c);
            for(int i = 0; i < n; i++)                      
            {
                memset(tm[i].q, 0, sizeof(tm[i].q));
                memset(tm[i].ed, 0, sizeof(tm[i].ed));
                memset(tm[i].edp, 0, sizeof(tm[i].edp));
                memset(tm[i].eds, 0, sizeof(tm[i].eds));
                memset(sum, 0, sizeof(sum));
                tm[i].point = s;
            }
            for(int i = 0; i < c; i++)                      //c次操作
            {
    
                int midn;
                scanf("%d", &midn);                         //midn次攻击
                for(int j = 0; j < midn; j++)
                {
                    int a, b, qc;
                    scanf("%d%d%d", &a, &b, &qc);
    
                    tm[b-1].edp[qc-1] = 1;
                    if(!tm[b-1].ed[qc-1][a-1])              //判断是否重复攻击(ac前最后一次wa)
                    {
                        tm[b-1].ed[qc-1][a-1] = 1;
                        tm[b-1].eds[qc-1]++;
                    }
    
                }
                if(midn > 0)                                //如果有攻击,则算分(也不知道是不是有效剪枝)
                {
                    for(int j = 0; j < n; j++)                      //n点被攻击
                    {
                        for(int k = 0; k < q; k++)
                        {
                            if(tm[j].edp[k] == 1)                   //k点被攻击
                            {
                                tm[j].point -= 1.0*(n-1);
    
                                for(int l = 0; l < n; l++)          
                                {
                                    if(tm[j].ed[k][l] == 1)         //l队攻击
                                    {
                                        tm[l].point += 1.0*(n-1)/tm[j].eds[k];
                                    }
                                }
    
                            }
                        }
                    }
                }
    
                for(int j = 0; j < q; j++)                  //各队个点状态判断
                {
                    int mid;
                    for(int k = 0; k < n; k++)
                    {
    
                        scanf("%d", &mid);
                        if(mid == 1)                        //状态不错
                        {
                            tm[k].q[j] = 1;
                            sum[j]++;                       //j点状态好的数目++
                        }
                    }
                    for(int k = 0; k < n; k++)              //算分
                    {
                        if(tm[k].q[j] == 0) tm[k].point -= 1.0*(n-1);
                        else tm[k].point += 1.0*(n-1)*(n-sum[j])/sum[j];
                    }
                }
    
                int cq;
                scanf("%d", &cq);                                   //cq次查询
                if(cq > 0)                                          //又是一个不知道有没有用的剪枝……
                {
                    for(int j = 0; j < n; j++)
                    {
                        sorting[j].p = tm[j].point;
                        sorting[j].flag = j;
                    }
                    sort(sorting, sorting+n, cmp);
                    sorting[0].r = 1;
                    for(int j = 1; j < n; j++)
                    {
                        if(fabs(sorting[j-1].p-sorting[j].p) < 0.00001 ) sorting[j].r = sorting[j-1].r;      //又是0.00001
                        else sorting[j].r = j+1;
                    }
    
                    for(int j = 0; j < cq; j++)
                    {
                        int miding;
                        scanf("%d", &miding);
                        printf("%.8f", tm[miding-1].point);
                        for(int k = 0; k < n; k++)                  //最搓的地方又一次出现,寻找对应队伍的排名,效率低的要死(居然这么挫……推荐大家看看别人的排序方法,我这个实在……但是我实在不想改了)
                        {
                            if(sorting[k].flag == miding-1) printf(" %d
    ", sorting[k].r);
                        }
                    }
                }
                update();
            }
        }
        return 0;
    }

      附上别人对队伍排名的操作——

     1 struct node1
     2 {
     3     int r;                                          //排名
     4     double p;                                       //得分
     5     int s;                                          //下标
     6 }sorting[N];
     7 
     8 bool cmp1(node1 x, node1 y)
     9 {
    10     return x.p - y.p > 0.00001                      //按得分排名
    11 }
    12 
    13 bool cmp2(node1 x, node1 y)
    14 {
    15     return x.s < y.s;                               //按下标排序
    16 }
    17 
    18 for(int i = 0; i < n; i++)
    19 {
    20     sorting[i].p = tm[i].p;
    21     sorting[i].s = i;
    22 }
    23 
    24 sort(sorting, sorting+n, cmp1);
    25 
    26 sorting[0].r = 1;
    27 for(int i = 1; i < n; i++)
    28 {
    29     if(fabs(sorting[i]-sorting[i-1]) < 0.00001) sorting[i].r = sorting[i-1].r;
    30     else sorting[i].r = i+1;
    31 }
    32 
    33 sort(sorting, sorting+n, cmp2);
  • 相关阅读:
    Windows10打印mumu模拟器日志
    简析快速排序
    数字转换为W,K,结尾,并可指定长度(仅供参考,个人测试使用。)
    简析选择排序
    简析冒泡排序
    NX二次开发 工程图创建孔表功能
    NX二次开发 建模座标和工程图座标映射
    NXOpen绝对座标值转为WCS座标值
    NX二次开发 结合包容盒快速创建WCS
    NX二次开发 数值转NXString字符
  • 原文地址:https://www.cnblogs.com/mypride/p/4472567.html
Copyright © 2011-2022 走看看