「SOL」SurroundingGame(TopCoder)

之前學過的內容,結果如今仍是不會……ios


題面

有一個 \(n\times m\) 的棋盤,你能夠花費 \(cost(i,j)\) 的代價在 \((i,j)\) 處放一顆棋子。網絡

若是格子 \((i,j)\) 知足下面條件之一時,你能夠獲得 \(value(i,j)\) 的收益:ide

  • \((i,j)\) 上有棋子;
  • \((i,j)\) 的全部相鄰的格子上都有棋子。

求「收益減花費」的最大值。spa

數據規模 \(n,m\le20\)code


解析

分析題目,大概能夠找到下面這些 0/1 變量blog

  • 格子 \((i,j)\) 是否放格子,記爲 \(f(i,j)\)
  • 格子 \((i,j)\) 周圍是否都有棋子,記爲 \(g(i,j)\)

假設咱們能夠不花費任何代價就得到所有收益,再計算最小的「額外損失=花費+損失收益」,即想到最小割模型——二元關係最小割。因而繼續分析變量的聯繫。ci

這些變量的兩兩聯繫也有兩類(這裏的「聯繫」指兩變量共同影響答案)get

  • \(f(i,j)\)\(g(i,j)\),額外損失表以下:string

    \(f(i,j)\) \ 右 \(g(i,j)\) 0 1
    0 \(value\) \(0\)
    1 \(cost\) \(cost\)
  • \(g(i,j)\) 和相鄰格子的 \(f\),限制就是:若是 \(g(i,j)=1\),則相鄰格子的 \(f\) 也爲 \(1\);能夠表示爲 \(g(i,j)=1,f(鄰)=0\) 的額外損失爲 \(+\infty\)it

接下來就是建圖,拿出二元關係最小割的模板,割左邊表示選 \(0\),割右邊表示選 \(1\)

對於 \(f(i,j)\)\(g(i,j)\) 的聯繫:

\[\begin{cases} a+c=value&(1)\\ b+d=cost&(2)\\ a+d+f=0&(3)\\ b+c+e=cost&(4) \end{cases} \]

發現 \(K=e+f=(3)+(4)-(1)-(2)=-value<0\),須要利用二分圖的性質反向,則把 \(g\) 的含義反轉,即割 \(c\) 表示選 \(1\),割 \(d\) 表示選 \(0\)。則新的方程爲:

\[\begin{cases} a+d+f=value\\ b+c+e=cost\\ a+c=0\\ b+d=cost\\ \end{cases} \]

直接解方程能夠獲得一組較簡單的解:\(b=cost,f=value,a=c=d=e=0\)

對於 \(g(i,j)\) 和相鄰的 \(f\) 的聯繫也能夠列出方程:

\[\begin{cases} a+c=+\infty\\ b+d=0\\ a+d+f=0\\ b+c+e=0 \end{cases} \]

仍然會發現 \(K=-\infty<0\),再次利用二分圖性質反向,可是 \(g\) 已經反過向了,只能把 \(f\) 反向——注意到方格圖的相鄰格子連邊是自然的二分圖,因此能夠 \(f\) 能夠反轉。獲得的方程是

\[\begin{cases} b+c+e=+\infty\\ a+d+f=0\\ b+d=0\\ a+c=0 \end{cases} \]

易得 \(e=+\infty,a=b=c=d=f=0\)

最後整理獲得流網絡以下:


源代碼

/*Lucky_Glass*/
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

const int N=405,M=N*6,INF=0x3f3f3f3f;
#define ci const int &

class SurroundingGame{
private:
    struct GRAPH{
        int head[N<<1],cap[M<<1],nxt[M<<1],to[M<<1],ncnt;
        GRAPH(){ncnt=1;}
        void AddEdge(ci u,ci v,ci varc){
            // printf("%d -> %d %d\n",u,v,varc);
            int p=++ncnt,q=++ncnt;
            to[p]=v,nxt[p]=head[u],head[u]=p,cap[p]=varc;
            to[q]=u,nxt[q]=head[v],head[v]=q,cap[q]=0;
        }
        inline int operator [](ci u){return head[u];}
    }Gr;
    int dep[N<<1],head[N<<1],St,Ed,n,m;
    inline int index(ci x,ci y,ci i){return 2*(x*m+y)+i;}
    bool BFS(){
        for(int i=1;i<=Ed;i++) dep[i]=-1,head[i]=Gr[i];
        queue<int> que;que.push(St),dep[St]=0;
        while(!que.empty()){
            int u=que.front();que.pop();
            for(int it=head[u];it;it=Gr.nxt[it]){
                int v=Gr.to[it];
                if((~dep[v]) || !Gr.cap[it]) continue;
                dep[v]=dep[u]+1;
                if(v==Ed) return true;
                que.push(v);
            }
        }
        return false;
    }
    int Aug(ci u,ci in){
        if(u==Ed) return in;
        int out=0;
        for(int &it=head[u];it;it=Gr.nxt[it]){
            int v=Gr.to[it];
            if(!Gr.cap[it] || dep[v]!=dep[u]+1) continue;
            int tov=Aug(v,min(in-out,Gr.cap[it]));
            out+=tov,Gr.cap[it]-=tov,Gr.cap[it^1]+=tov;
            if(in==out) break;
        }
        return out;
    }
    int Dinic(){
        int ret=0;
        while(BFS()) ret+=Aug(St,INF);
        return ret;
    }
    int charint(const char &c){
        if('0'<=c && c<='9') return c-'0';
        if('a'<=c && c<='z') return c-'a'+10;
        return c-'A'+36;
    }
    bool law(ci x,ci y){return 0<=x && x<n && 0<=y && y<m;}
public:
    int maxScore(vector<string> cost,vector<string> value){
        n=cost.size(),m=cost[0].length();
        St=n*m*2+1,Ed=St+1;
        const int DIR[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
        int ans=0;
        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++){
                if((i+j)&1){
                    Gr.AddEdge(St,index(i,j,1),charint(cost[i][j]));
                    Gr.AddEdge(index(i,j,1),index(i,j,2),charint(value[i][j]));
                    for(int k=0;k<4;k++){
                        int p=i+DIR[k][0],q=j+DIR[k][1];
                        if(law(p,q)) Gr.AddEdge(index(i,j,2),index(p,q,1),INF);
                    }
                }
                else{
                    Gr.AddEdge(index(i,j,1),Ed,charint(cost[i][j]));
                    Gr.AddEdge(index(i,j,2),index(i,j,1),charint(value[i][j]));
                    for(int k=0;k<4;k++){
                        int p=i+DIR[k][0],q=j+DIR[k][1];
                        if(law(p,q)) Gr.AddEdge(index(p,q,1),index(i,j,2),INF);
                    }
                }
                ans+=charint(value[i][j]);
            }
        return ans-Dinic();
    }
}test;

THE END

Thanks for reading!

\[\begin{split} 「\ &杏花吹落後\ 衣袂當風\\ &都去得匆匆\ 卻恨誰的背影太從容\\ &這故事難道無關癢痛\\ &來勢洶洶\ 悵然得連旁人都傳頌\\ &到頭去如何\ 心底猶空\ 」\\ ——&\text{《何日重到蘇瀾橋》By 泠鳶yousa} \end{split} \]

> By 何日重到蘇瀾橋-Bilibili

相關文章
相關標籤/搜索