其他分享
首页 > 其他分享> > Retiling-Google Codejam 2021 Round 2

Retiling-Google Codejam 2021 Round 2

作者:互联网

Retiling-Google Codejam 2021 Round 2第四题

Cody-Jamal’s latest artistic installment is a tiled kitchen floor that can be retiled to different patterns. The floor consists of a matrix of R rows and C columns of square tiles. Each tile is reversible, one side is magenta and the other one is green.
To retile the kitchen, there are two allowed operations:
flip a tile, changing its visible color from magenta to green, or vice versa, and swap two adjacent tiles (horizontally or vertically, but not diagonally), without flipping either.
Viewing Cody-Jamal’s artistic floor is free, but interacting with it is not. Performing a single flip operation costs F coins, and performing a single swap operation costs S coins.
You can see the current state of the floor and want to turn it into a particular pattern. What is the minimum amount of coins you need to spend to achieve your goal?

题目大意:

你需要在一个长宽分别为 R , C ( 1 ≤ R , C ≤ 10 ) R,C(1\leq R,C\leq10) R,C(1≤R,C≤10)的房间重新铺地砖。地砖正面是绿色,背面是红色,你每次可以把一个地砖翻面,或是把两个相邻的地砖(仅限上下左右相邻)交换。一次翻面花费为 F F F,一次交换花费为 S S S。现在给定所有地砖位置的初始颜色和最终颜色,试计算最小花费。

思路分析:

注意到对于每一块地砖,在最优解法中不会既被翻面又被交换:假设地砖 x x x和地砖 y y y交换后又被翻面,这等价于我们翻面地砖 y y y,这样花费显然更小。同时,交换操作显然只在颜色不同的两个地砖之间进行。

那么解法就很显然了:我们考虑所有初始颜色和最终颜色不一样的位置,根据颜色分组,这就是一个二分图的匹配问题:我们考虑匹配两个起始颜色不同的地砖进行匹配,完成最优匹配后剩下的地砖进行翻转操作即可。交换的花费为 m i n ( d i s t ( x , y ) × S , 2 × F ) min(dist(x,y)\times S,2\times F) min(dist(x,y)×S,2×F)(我们也可以选择直接把两块地砖都翻面)。我们可以使用最优匹配算法解决这个问题。由于点数是100,边数最多是50 × \times × 50=2500条,我们过时限是绰绰有余的。

这里我直接采用了费用流算法,时间上不会有什么差异,主要是KM写得少。

重要部分代码:

加边:

 for(int i=0;i<r*c;i++){
 		if(diff[i])countdi++;//算一下总共需要改的地砖
        if(color[i]=='G'&&diff[i])//绿色且需要修改的地砖
        {
            for(int j=i+1;j<r*c;j++){
                if(color[j]=='M'&&diff[j])//与红色且需要修改的地砖配对
                {
                    add(i,j,1,min(dist(i,j)*costS,2*cost*F))//流量为1,费用如上所述;
                }
            }
            add(S,i,1,0)//别忘了连条边到源点;
        }
        else if(if(color[i]=='M'&&diff[i]))add(i,T,1,0);//红色的需要改的要连一条边到汇点
    }

费用流板子:

int cost=0,flow=0;
    while(spfa()){
        flow+=limit[T];
        cost+=limit[T]*dis[T];
        for(int i=T;i!=S;i=to[pre[i]^1]){
            f[pre[i]]-=limit[T];
            f[pre[i]^1]+=limit[T];
        }
    }
    cost+=costF*(countdi-flow*2);//把未匹配成功的地砖翻面费用加上·1

费用流spfa板子:

inline bool spfa(){
    memset(dis,0x3f,sizeof dis);
    memset(limit,0,sizeof limit);
    dis[S]=0,q.push(S),limit[S]=0x3f3f3f3f,st[S]=true;
    while(!q.empty()){
        int x=q.front();
        q.pop();
        st[x]=false;
        for(int i=h[x];~i;i=nex[i]){
            int j=to[i];
            if(f[i]&&dis[j]>dis[x]+w[i]){
                dis[j]=dis[x]+w[i];
                limit[j]=min(limit[x],f[i]);
                pre[j]=i;
                if(!st[j]){
                    q.push(j);
                    st[j]=true;
                }
            }
        }
    }
    return limit[T]>0;
}

第二轮压轴题,二分图模型比较明显,所以说并不难。

标签:Google,地砖,int,st,翻面,Retiling,limit,2021,dis
来源: https://blog.csdn.net/Layomiiety/article/details/116886768