相當神奇的費用流拆點模型
最開始我想到把交換黑色棋子看成乙個流流動的過程,流從乙個節點流向另乙個節點就是交換兩個節點,然後把乙個位置拆成兩個點限制流量,然後就有了這樣的建圖方法
s向所有初始是黑色點的入點連cap=1,cost=0的邊,最後是黑色點的出點向t連一條cap=1,cost=0的邊,然後對應點的出點向它八連通的點的入點連一條cap=inf,cost=1的邊,每個點的入點向出點連一條cap=limit,cost=0的邊
看起來很靠譜,實際是假的
因為我們剛才的方法沒有考慮到一條交換路徑的兩個端點只交換一次並且路徑上其他點都交換了兩次(也就是端點和路徑上的其他點沒有區別)
所以可以拆成三層圖。
s向每個初始黑點的mid連邊,每個最終黑點的mid向t連邊,相鄰點連邊不變,
然後懶得講了。。。。
···cpp
using namespace std;
struct edge;
const int maxn = 1550;
const int inf = 0x3f3f3f3f;
vectoredges;
vectorg[maxn];
int d[maxn],p[maxn],a[maxn],vis[maxn],s,t,n,m;
queueq;
void addedge(int u,int v,int cap,int cost));
edges.push_back((edge));
int cnt=edges.size();
g[u].push_back(cnt-2);
g[v].push_back(cnt-1);
}bool spfa(int &cost,int &flow)
return true;
}void mcmf(int &cost,int &flow)
inline int id(int x,int y)
char s[50];
int pre_map[30][30],bac_map[30][30];
int main()
pre_map[i][j]=s[j]-'0';}}
for(int i=1;i<=n;i++)
bac_map[i][j]=s[j]-'0';}}
if(cntb1!=cntb2)
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(j!=1)
if(i!=n)
if(j!=m)
if(i!=1&&j!=1)
if(i!=n&&j!=1)
if(i!=1&&j!=m)
if(i!=n&&j!=m)
}for(int i=1;i<=n;i++)
if(pre_map[i][j]0&&bac_map[i][j]1)
if(pre_map[i][j]bac_map[i][j])}}
int cost=0,flow=0;
mcmf(cost,flow);
printf("%d\n",cost);
return 0;
}
P3159 CQOI2012 交換棋子
有乙個n行m列的黑白棋盤,你每次可以交換兩個相鄰格仔 相鄰是指有公共邊或公共頂點 中的棋子,最終達到目標狀態。要求第i行第j列的格仔只能參與mi,j次交換。第一行包含兩個整數n,m 1 n,m 20 以下n行為初始狀態,每行為乙個包含m個字元的01串,其中0表示黑色棋子,1表示白色棋子。以下n行為目...
P3159 CQOI2012 交換棋子 網路流
有乙個n行m列的黑白棋盤,你每次可以交換兩個相鄰格仔 相鄰是指有公共邊或公共頂點 中的棋子,最終達到目標狀態。要求第i行第j列的格仔只能參與mi,j次交換。輸入格式 第一行包含兩個整數n,m 1 n,m 20 以下n行為初始狀態,每行為乙個包含m個字元的01串,其中0表示黑色棋子,1表示白色棋子。以...
2668 cqoi2012 交換棋子
time limit 3 sec memory limit 128 mb submit 1136 solved 423 submit status discuss 有乙個n行m列的黑白棋盤,你每次可以交換兩個相鄰格仔 相鄰是指有公共邊或公共頂點 中的棋子,最終達到目標狀態。要求第i行第j列的格仔只能...