費用流題,構圖非常巧妙。
考慮每個點的交換限制的約束,一看就知道是點容量,但是這裡不是一分為二,而是一分為三。
首先我們把問題化簡,變成對於原圖上所有黑點,找到乙個新圖中的黑點,進行多次交換後到達。我們看到多次交換實際上是走了一條路徑(這裡不是最短路)。對於這條路徑的起點和終點,僅進行了1次交換,而路徑上的其他點都交換了2次。所以我們需要構造一種圖來把這個交換次數的差異體現出來,於是:
對於每個點一分為三,分為p0,p1,p2,對於每個點,如果它是原圖中得黑點,連邊,,;如果它是新圖中得黑點,連邊,,;如果它在兩個圖中都是白點,那麼連邊,。這樣就可以體現出點容量的差異了。
然後對於原圖中可以交換的兩個點(i,j)連線,那麼這種邊每流過1的流量就意味著(i,j)交換了一次,那麼費用就是最終的答案了。
chess
1 #include2 #include3 #include4 #include5 #include6#define maxn 2000
7#define maxm 50000
8#define inf 2147483647
9using
namespace
std;
10struct
et11
e[maxm];
14char s1[100][100],s2[100][100],s3[100][100
];15
int a[100][100],b[100][100],c[100][100],num[100][100
];16
intfir[maxn],q[maxm],d[maxn],pre[maxn];
17bool
inque[maxn];
18int
n,m,st,ed,tot,ans,b1,b2,fare;
1920
bool
find()
2137
}38 inque[now]=0;39
}40return d[ed]
4243
void
fare_flow()
4454
}
5556
void add(int x,int y,int z,int
w)57
6162
intmain()
6383
for (int i=1;i<=n;i++)
84for (int j=1;j<=m;j++)
8594
else
95if
(b[i][j])
96101
else
102106
}107
for (int i=1;i<=n;i++)
108for (int j=1;j<=m;j++)
109119
//for (int i=2;i<=tot;i++) cout<120 fare=0
;121
if (b1==b2)
125else fare=-1
;126 printf("
%d\n
",fare);
127return0;
128 }
BZOJ 2668 cqoi2012 交換棋子
time limit 3 sec memory limit 128 mb submit 1112 solved 409 submit status discuss 有乙個n行m列的黑白棋盤,你每次可以交換兩個相鄰格仔 相鄰是指有公共邊或公共頂點 中的棋子,最終達到目標狀態。要求第i行第j列的格仔只能...
BZOJ2668 cqoi2012 交換棋子
題解 可以戳這裡 其實自己yy一下就知道這樣建圖的正確性了。感覺太神奇,居然還能拆成3個點 orzzzzzzzzzzzzzzzzzzzzzzzzz 跪跪跪跪跪跪跪跪 1 include2 3 include4 5 include6 7 include8 9 include10 11 include1...
bzoj2668 cqoi2012 交換棋子
description 有乙個 n 行 m 列的黑白棋盤,你每次可以交換兩個相鄰格仔 相鄰是指有公共邊或公共頂點 中的棋子,最終達到目標狀態。要求第 i 行第 j 列的格仔只能參與 m 次交換。input 第一行包含兩個整數 n,m 1 le n,m le 20 以下 n 行為初始狀態,每行為乙個包...