zoukankan      html  css  js  c++  java
  • 三国游戏

    试题描述

        小涵很喜欢电脑游戏,这些天他正在玩一个叫做《三国》的游戏。在游戏中, 小涵和计算机各执一方,组建各自的军队进行对战。 游戏中共有 N位武将 (N为偶数且不小于 4) ,任意两个武将之间有一个“默契值”,表示若此两位武将作为一对组合作战时,该组合的威力有多大。游戏开始前,所有武将都是自由的(称为自由武将,一旦某个自由武将被选中作为某方军队的一员,那么他就不再是自由武将了),换句话说,所谓的自由武将不属于任何一方。游戏开始,小涵和计算机要从自由武将中挑选武将组成自己的军队,规则如下:小涵先从自由武将中选出一个加入自己的军队,然后计算机也从自由武将中选出一个加入计算机方的军队。接下来一直按照“小涵→计算机→小涵→……”的顺序选择武将,直到所有的武将被双方均分完。然后,程序自动从双方军队中各挑出一对默契值最高的武将组合代表自己的军队进行二对二比武,拥有更高默契值的一对武将组合获胜,表示两军交战,拥有获胜武将组合的一方获胜。已知计算机一方选择武将的原则是尽量破坏对手下一步将形成的最强组合,它采取的具体策略如下:任何时刻,轮到计算机挑选时,它会尝试将对手军队中的每个武将与当前每个自由武将进行一一配对,找出所有配对中默契值最高的那对武将组合,并将该组合中的自由武将选入自己的军队。下面举例说明计算机的选将策略,例如,游戏中一共有 6个武将,他们相互之间的默契全值如下表所示武将编号:

            

    双方选将过程如下所示:
                      小涵      轮到计算机时可选的自由武将    计算机     
            第一轮     5        1 2 3 4 6                     4          
            第二轮     5 3      1 2 6                         4 1    
            第三轮     5 3 6    2                             4 1 2      
        小涵想知道,如果计算机在一局游戏中始终坚持上面这个策略,那么自己有没有可能必胜?如果有,在所有可能的胜利结局中,自己那对用于比武的武将组合的默契值最大是多少?假设整个游戏过程中,对战双方任何时候均能看到自由武将队中的武将和对方军队的武将。为了简化问题,保证对于不同的武将组合,其默契值均不相同。

    输入
    第1行为一个偶数N,表示武将的个数。 第2行到第N行里,第(i+1)行有(N-i)个非负整数,每两个数之间用一个空格隔开,表示i号武将和i+1,i+2,……,N号武将之间的默契值(0≤默契值≤1,000,000,000) 。 
    输出
    若对于给定的游戏输入,存在可以让小涵获胜的选将顺序,则输出 1,并另起一行输出所有获胜的情况中,小涵最终选出的武将组合的最大默契值。如果不存在可以让小涵获胜的选将顺序,则输出 0。 
    输入示例
    【输入样例 1】 

    5 28 16 29 27 
    23 3 20 1 
    8 32 26 
    33 11 
    12 

    【输入样例 2】 

    42 24 10 29 27 12 58 
    31 8 16 26 80 6 
    25 3 36 11 5 
    33 20 17 13 
    15 77 9 
    4 50 
    19 
    输出示例
    【输出样例 1】 

    32 
    【输出样例 2】 

    77
    其他说明
    数据范围:N≤500。

    从思想实现来说,还是一道枚举加贪心的题目。因为,“人”在和计算机斗争的过程中,双方都无法取得最大的默契配合值。所以,“人”只能够去考虑次大最优值,但是,为了能够骗过计算机,我们选择的,只能够是跟我们选择的第一位武将配合值次大的那位武将(如果不是一个的话也会被计算机破坏掉)。所以,就要求我们必须,找到,每行中次大值最大的那个值(挺扰人的)。当然,这个提法是建立在我们有了题目中展示的那个矩阵之后。你要注意,题目给你的值是这个矩阵的右半边,你需要把左半边的值自己不上,才能够按照行去枚举(当然,做完后,如果你想按照列,也没有关系,因为全都是对称的,对吧)。

    当然,可能有同学考虑到了0的难问题。很遗憾,这道题肯定不会出现零。因为,计算机只能破坏“人”,而且,我也想到了骗他的方法,计算机必输无疑。

    下面看一下程序的核心部分:

    输入部分:

    for (i = 1 ; i < n ; i++)
          for (j = i + 1 ; j <= n ; j++ )
            cin >> s[i][j];

    对称复制部分:

    for (i = 2 ; i <= n ; i++)
          for (j = 1 ; j < i ; j++)
            s[i][j] = s[j][i];

    找每行次大值中的最大值部分:

      for (i = 1 ; i <= n ; i++)
        {
          t1 = t2 = 0;
          for (j = 1 ; j <= n ; j++)
          {
            if (s[i][j] > t1) t1 = s[i][j];
            if (t1 > t2) swap(t1, t2);
          }
          if (t < t1) t = t1;
        }

    很明显,t为每行次大值(t1)的最大值。也就是我们的所求。

     

    完整C++程序:

    #include <iostream>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    
    int a[505][505];
    int main(){
        int n;
        cin >> n;
        for(int i = 1; i < n; ++i){
          for(int j = i + 1; j <= n; ++j){
             cin >> a[i][j];
          }
       }
       for(int i = 2; i <= n; ++i){
          for(int j = 1; j < i; ++j){
            a[i][j] = a[j][i];
          }
       }
       int jsj = 0;
       for(int i = 1; i <= n; ++i){
          int js1 = 0;
          int js2 = 0;
          for(int j = 1; j <= n; ++j){
            if(a[i][j] > js1) js1 = a[i][j];
            if(js1 > js2){
                  int js = js1;
                  js1 = js2;
                  js2 = js;
            }
          }
          if(jsj < js1) jsj = js1;
        }
        if(jsj == 0){
            cout << jsj << endl;
        }else{
            cout << '1' << endl;
          cout << jsj << endl;
        }
    }
  • 相关阅读:
    hdu 5646 DZY Loves Partition
    bzoj 1001 狼抓兔子 平面图最小割
    poj 1815 Friendship 最小割 拆点 输出字典序
    spoj 1693 Coconuts 最小割 二者取其一式
    hdu 5643 King's Game 约瑟夫环变形
    约瑟夫环问题
    hdu 5642 King's Order
    CodeForces 631C Report
    1039: C语言程序设计教程(第三版)课后习题9.4
    1043: C语言程序设计教程(第三版)课后习题10.1
  • 原文地址:https://www.cnblogs.com/WHYFRANK/p/4717719.html
Copyright © 2011-2022 走看看