1414:Life Line【2019北大夏令营E】

1414:Life Line【2019夏令营E】

  • 查看

  • 提交

  • 统计

  • 提示

  • 提问

  • 总时间限制:

    1000ms

  • 内存限制:

    65536kB

  • 描述

    Let’s play a new board game “Life Line”.

    The number of the players is greater than 1 and less than 10.

    In this game, the board is a regular triangle in which many small regular triangles are arranged (See Figure 1). The edges of each small triangle are of the same length. img The size of the board is expressed by the number of vertices on the bottom edge of the outer triangle.For example, the size of the board in Figure 1 is 4.

    At the beginning of the game, each player is assigned his own identification number between 1 and 9,and is given some stones on which his identification number is written. Each player puts his stone in turn on one of the “empty” vertices. An “empty vertex” is a vertex that has no stone on it. When one player puts his stone on one of the vertices during his turn, some stones might be removed from the board. The player gains points which is equal to the number of the removed stones of himself. The points of a player for a single turn is the points he gained minus the points he lost in that turn.

    The conditions for removing stones are as follows :

    1.The stones on the board are divided into groups. Each group contains a set of stones whose numbers are the same and placed adjacently. That is, if the same numbered stones are placed adjacently,they belong to the same group.

    2.If none of the stones in a group is adjacent to at least one “empty” vertex, all the stones in that group are removed from the board. img Figure 2 shows an example of the groups of stones. Suppose that the turn of the player ‘4’ comes now. If he puts his stone on the vertex shown in Figure 3a, the conditions will be satisfied to remove some groups of stones (shadowed in Figure 3b). The player gains 6 points, because the 6 stones of others are removed from the board (See Figure 3c). img As another example, suppose that the turn of the player ‘2’ comes in Figure 2. If the player puts his stone on the vertex shown in Figure 4a, the conditions will be satisfied to remove some groups of stones (shadowed in Figure 4b). The player gains 4 points, because the 4 stones of others are removed. But, at the same time, he loses 3 points, because his 3 stones are removed. As the result, the player’s points of this turn is 4 - 3 = 1 (See Figure 4c). img When each player puts all of his stones on the board, the game is over. The total score of a player is the summation of the points of all of his turns. Your job is to write a program that tells you the maximum points a player can get (i.e., the points he gains - the points he loses) in his current turn.

  • 输入

    The input consists of multiple data. Each data represents the state of the board of the game still in progress. The format of each data is as follows. N C S1,1 S2,1 S2,2 S3,1 S3,2 S3,3 . . . SN,1 . . . SN,N N is the size of the board (3 <= N <= 10). C is the identification number of the player whose turn comes now (1 <= C <= 9). That is, your program must calculate his points in this turn. Si,j is the state of the vertex on the board (0 <= Si,j <= 9). If the value of Si,j is positive, it means that there is the stone numbered by Si,j there. If the value of Si,j is 0, it means that the vertex is “empty”. Two zeros in a line, i.e., 0 0, represents the end of the input.

  • 输出

    For each data, the maximum points the player can get in the turn should be output, each in a separate line.

  • 样例输入

    4 4
       2
      2 3
     1 0 4
    1 1 4 0
    4 5
       2
      2 3
     3 0 4
    1 1 4 0
    4 1
       2
      2 3
     3 0 4
    1 1 4 0
    4 1
       1
      1 1
     1 1 1
    1 1 1 0
    4 2
       1
      1 1
     1 1 1
    1 1 1 0
    4 1
       0
      2 2
     5 0 7
    0 5 7 0
    4 2
       0
      0 3
     1 0 4
    0 1 0 4
    4 3
       0
      3 3
     3 2 3
    0 3 0 3
    4 2
       0
      3 3
     3 2 3
    0 3 0 3
    6 1
         1
        1 2
       1 1 0
      6 7 6 8
     0 7 6 8 2
    6 6 7 2 2 0
    5 9
        0
       0 0
      0 0 0
     0 0 0 0
    0 0 0 0 0
    5 3
        3
       3 2
      4 3 2
     4 4 0 3
    3 3 3 0 3
    0 0
    
  • 样例输出

    6
    5
    1
    -10
    8
    -1
    0
    1
    -1
    5
    0
    5
    

题解

  • 理解题意:

    • “none of the stones in a group is adjacent to at least one “empty” vertex”是对于在空位置上放上棋子之后,对于每个group的拓扑进行判断(然后同时移除)
  • 所有连通分量(连通且stone号相同),然后对于每个empty顶点e,判断放入C的得分

    • 对于非C连通分量,如果没有e之外的empty邻居,则会被移除

    • 对于所有C连通分量包括顶点e,如果存在e之外的empty邻居,则不会被移除(都不存在e之外的empty邻居才会被移除)

      • 因为放入e之后,所有C连通分量包括e会成为一个C连通分量,是一个group

      • 包括了“没有C连通分量、仅有顶点e且e没有其他empty邻居”的情况

  • 时间复杂度:

    • empty顶点数目最多O(N2):找所有连通分量O(N2),遍历所有连通分量从而计分最多O(N2)(连通分量最多O(N2)个),所以O(N2*N2)=O(N4) N<=10则10^4
      • 棋盘顶点数目O(N^2)
#include <iostream>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <queue>
#include <climits>

using namespace std;
#define MAXNODE 60
#define MAXN 12
int chess[MAXNODE];
struct Comp
{
    int node_num;
    int empty_nbr_num;
    Comp(int n0,int e0):node_num(n0),empty_nbr_num(e0){}
};
void insert_edge(unordered_map<int,vector<int>>&nbrs, unordered_map<int,vector<int>>&empty_enbrs,int node_id, int l)
{
    nbrs[node_id].push_back(l);
    nbrs[l].push_back(node_id);
    if(chess[node_id]==0 && chess[l]==0){
        empty_enbrs[node_id].push_back(l);
        empty_enbrs[l].push_back(node_id);
    }
}
int main()
{
    int N,C;
    int node_id;
    while(cin>>N>>C && (N||C)){
        node_id=0;
        vector<int>empty_node;
        int c;
        unordered_map<int,vector<int>>nbrs;
        unordered_map<int,vector<int>>empty_enbrs;
        for(int i=0; i<N; ++i){
            for(int j=0; j<=i; ++j){
                cin>>c;
                if(c==0){
                    empty_node.push_back(node_id);
                }
                chess[node_id++]=c;
            }
        }
        int tmp=0;
        for(int i=0; i<N-1; ++i){
            for(int j=0; j<=i; ++j){
                //triangle: tmp tmp+i+1 tmp+i+2
                int l=tmp+i+1;
                int r=tmp+i+2;
                insert_edge(nbrs,empty_enbrs,tmp,l);
                insert_edge(nbrs,empty_enbrs,tmp,r);
                insert_edge(nbrs,empty_enbrs,r,l);
                ++tmp;
            }
        }

       
        unordered_map<int,vector<Comp>> empty2comps,empty2Ccomps;
        int comp_sz;
        unordered_set<int>empty_nbrs;
        //bfs for comp
        int visited[MAXNODE]={0};//mark when pushing into queue(one node might be the same neighbor of different nodes)
        for(int i=0; i<node_id; ++i){
            if(visited[i]==0 && chess[i]){
                comp_sz=0;
                empty_nbrs.clear();
                //bfs
                c=chess[i];
                queue<int>q;
                q.push(i);visited[i]=1;
                int curr;
                while(q.empty()==0){
                    curr=q.front();q.pop();
                    ++comp_sz;
                    for(int nbr:nbrs[curr]){
                        if(chess[nbr]==0){
                            empty_nbrs.insert(nbr);
                        }
                        if(chess[nbr]==c && visited[nbr]==0){
                            q.push(nbr);
                            visited[nbr]=1;
                        }
                    }
                }
                int empty_nbrs_sz=empty_nbrs.size();
                if(c==C){
                    for(int e:empty_nbrs){
                        empty2Ccomps[e].emplace_back(comp_sz,empty_nbrs_sz);
                    }
                }else{
                    if(empty_nbrs_sz<=1){
                        for(int e:empty_nbrs){
                            empty2comps[e].emplace_back(comp_sz,empty_nbrs_sz);
                        }
                    }
                }
            }
        }

        int max_score=INT_MIN;
        for(int e:empty_node){
            //cout<<"empty:"<<e<<" "<<chess[e]<<endl;
            int score=0;
            //add
            for(Comp cp:empty2comps[e]){
                score+=cp.node_num;
            }
            //del
            int del_score=0;
            //check whether has other empty nbr besides e
            //note this added stone's empty nbr need to considered
            bool has_other_nbr=(empty_enbrs[e].size()>0);
            for(Comp cp:empty2Ccomps[e]){
                del_score+=cp.node_num;
                if(cp.empty_nbr_num>1){
                    has_other_nbr=1;
                }
            }
            if(has_other_nbr==0){//after connect, no empty nbr
                score-=del_score;
                --score;
            }
            //cout<<"score:"<<score<<endl;
            if(score>max_score){
                max_score=score;
            }
        }
        cout<<max_score<<endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值