CQOI2012 交換棋子(拆點 費用流)

2022-03-16 22:59:48 字數 1285 閱讀 2740

(注意相鄰交換指的是八連通)

顯然可以將黑白交換看做只有黑色棋子在空棋盤上移動

交換限制交給流量,那麼有代價自然就是費用流了

考慮直接將兩個相鄰格仔連起來,由於交換次數是相對單個格仔而言的,流量無法確定

既然交換次數是單個格仔的屬性,自然可以考慮到拆點來表示其屬性

考慮將乙個格仔拆成入點和出點,中間連一條邊,流量為交換次數;但是想象乙個黑色棋子從1->2->3,那麼中間格仔用了兩次,兩邊格仔只用了一次,這個路徑就沒法用兩個點表示了

繼續拆,拆成三個點,入點出點和中間點,中間點即為黑色格仔所在位置,移動操作相當於中間點->出點->入點->中間點;我們在中間點->出點,入點->中間點這兩個地方限流;

發現如果乙個位置初始是黑點,最終是白點,那麼出去的流量顯然為進來的流量+1,其餘同理

所以將交換次數平分給進來和出去兩個地方,分情況討論「1」的分配

其他的邊很好想,連好後跑一次mcmf即可

#include#define n 2005

#define m 200005

using namespace std;

const int inf = 100000000;

int n,m,s,t,maxflow,mincost;

int pre[n],preedge[n],flow[n];

int exist[n],dis[n];

int dox[8]=;

int doy[8]=;

char st[25][25],ed[25][25],lim[25][25];

struct edge

edge[m<<1];int head[n],cnt=1;

void add_edge(int from,int to,int flow,int dis)

void add(int from,int to,int flow,int dis)

int get_id(int x,int y,int c)

bool spfa()

}} }

return (pre[t] != -1);

}void mcmf() }}

int main()

else if(st[i][j-1]=='0' && ed[i][j-1]=='1')

else

//八連通

for(int k=0;k<8;++k)

}} mcmf();

if(maxflow != sum) cout<<-1

}

題解 CQOI2012交換棋子

感受到網路流的強大了 這道題目的關鍵在於 前後顏色不變的,流入流出的次數相等 原本是黑色的最後變成了白色,流出比流入次數多1 原本是白色最後變成黑色,流入比流出次數多一。所以我們將每一點拆成3個點,分別代表流入點,原點與流出點。最開始為黑色的點與源點連流量為1,費用為0的邊,最後為黑色的點與匯點連流...

CQOI2012 交換棋子 費用流

有乙個n行m列的黑白棋盤,你每次可以交換兩個相鄰格仔 相鄰是指有公共邊或公共頂點 中的棋子,最終達到目標狀態。要求第i行第j列的格仔只能參與mi,j次交換。乙個點拆三份,入點,主點,出點 入點向主點連邊,主點向出點連邊,設該點允許的交換次數為 x 根據以下規則確定 s to 初態點,末態點 to t...

CQOI2012 交換棋子 網路流 費用流

有乙個n行 m列的黑白棋盤,你每次可以交換兩個相鄰格仔 相鄰是指有公共邊或公共頂點 中的棋子,最終達到目標狀態。要求第i行第j列的格仔只能參與mi j次交換。第一行包含兩個整數n,m 1 n,m 20 以下n 行為初始狀態,每行為乙個包含 m個字元的 01串,其中 0表示黑色棋子,1表示白色棋子。以...