思路:题意很明显,求出配对的最优方案。这里我用的最大流做法,将每对的关系看成一条价值为1的边,Ek寻找价值最大的边。
先建模,将m个外籍空军与源点相连,n个英军与t相连,然后求从s->t的最大流。在每次减去通路最小权时候,确立外籍空军和英军的关系。
更新一下 我在初始化做了改进,觉得比以前的那个更好理解。
for(int i = 1; i <= m; i++) {
add(s, i, 1);
add(i, s, 0);
}
for(int i = m + 1; i <= n+m; i++) {
add(i, t, 1);
add(t, i, 0);
}
这样使外籍 和 英军分别链接 s和t 不会有冲突 且更有可读性
/**
* From:
* Qingdao Agricultural University
* Created by XiangwangAcmer
* Date : 2019-10-08-20.19.40
* Talk is cheap.Show me your code.
*/
using namespace std;
const ll maxn = 1e6 + 5;
const ll minn = 1e9 + 5;
const ll mod = 1000000007;
const int inf = 0x3f3f3f3f;
const long long LIMIT = 4294967295LL;
vector<int>v[maxn];
int dp[maxn];
vector<int>G[maxn];
bool row[maxn], col[maxn], vis[maxn];
bool flag = 0;
queue<int>q;
int n, m, s, t;
int ansk[1010];
struct node {
int v;
int w;
int next;
} Node[maxn];
int cnt = 0, head[maxn];
void add(int u, int v, int w) {
Node[++cnt].v = v;
Node[cnt].w = w;
Node[cnt].next = head[u];
head[u] = cnt;
}
struct Pre { ///记录路径
int v;
int edge;
} pre[maxn];
bool bfs(int s) { ///将源点放进来
queue<int>q;
mem(vis, 0);
mem(pre, -1);
vis[s] = 1;
q.push(s);
while(!q.empty()) {
int u = q.front();
q.pop();
for(int i = head[u]; ~i; i = Node[i].next) {
int d = Node[i].v;
if(!vis[d] && Node[i].w) {
pre[d].v = u;///该点的前一个点
pre[d].edge = i;
if(d == t)return 1;
vis[d] = 1;
q.push(d);
}
}
}
return 0;
}
int Ek() {
int ans = 0;
while(bfs(s)) {
int mi = inf;
for(int i = t; i != s; i = pre[i].v) {
mi = min(mi, Node[pre[i].edge].w);
}
for(int i = t; i != s; i = pre[i].v) {
ansk[pre[i].v] = i;
Node[pre[i].edge].w -= mi;
Node[pre[i].edge ^ 1].w += mi;
}
ans += mi;
}
return ans;
}
int main() {
cin>>m>>n;
mem(head, -1);
cnt=1;
t = 1009;
s = 1008;
for(int i = 1; i <= m; i++) {
add(s, i, 1);
add(i, s, 0);
}
for(int i = m + 1; i <= n+m; i++) {
add(i, t, 1);
add(t, i, 0);
}
while(1) {
int u, v;
cin>>u>>v;
if(u==-1&&v==-1)
break;
add(u, v , 1);
add(v , u, 0);
}
int T=Ek();
if(T == 0) {
cout << "No Solution!" << endl;
return 0;
}
cout << T << endl;
T=m;
for(int i = 1; i <= T; i++)
if(ansk[i] != 0)
cout << i << ' ' << ansk[i] << endl;
return 0;
}
/**
* From:
* Qingdao Agricultural University
* Created by XiangwangAcmer
* Date : 2019-10-08-20.19.40
* Talk is cheap.Show me your code.
*/
using namespace std;
const ll maxn = 1e6 + 5;
const ll minn = 1e9 + 5;
const ll mod = 1000000007;
const int inf = 0x3f3f3f3f;
const long long LIMIT = 4294967295LL;
vector<int>v[maxn];
int dp[maxn];
vector<int>G[maxn];
bool row[maxn], col[maxn], vis[maxn];
bool flag = 0;
queue<int>q;
int n, m, s, t;
int ansk[1010];
struct node {
int v;
int w;
int next;
} Node[maxn];
int cnt = 0, head[maxn];
void add(int u, int v, int w) {
Node[++cnt].v = v;
Node[cnt].w = w;
Node[cnt].next = head[u];
head[u] = cnt;
}
struct Pre { ///记录路径
int v;
int edge;
} pre[maxn];
bool bfs(int s) { ///将源点放进来
queue<int>q;
mem(vis, 0);
mem(pre, -1);
vis[s] = 1;
q.push(s);
while(!q.empty()) {
int u = q.front();
q.pop();
for(int i = head[u]; ~i; i = Node[i].next) {
int d = Node[i].v;
if(!vis[d] && Node[i].w) {
pre[d].v = u;///该点的前一个点
pre[d].edge = i;
if(d == t)return 1;
vis[d] = 1;
q.push(d);
}
}
}
return 0;
}
int Ek() {
int ans = 0;
while(bfs(s)) {
int mi = inf;
for(int i = t; i != s; i = pre[i].v) {
mi = min(mi, Node[pre[i].edge].w);
}
for(int i = t; i != s; i = pre[i].v) {
ansk[pre[i].v] = i;
Node[pre[i].edge].w -= mi;
Node[pre[i].edge ^ 1].w += mi;
}
ans += mi;
}
return ans;
}
int main() {
cin>>m>>n;
mem(head, -1);
cnt=1;
t = 1009;
s = 1008;
for(int i = 1; i <= n; i++) {
add(i + n, t, 1);
add(t, i + n, 0);
}
for(int i = 1; i <= m; i++) {
add(s, i, 1);
add(i, s, 0);
}
while(1) {
int u, v;
cin>>u>>v;
if(u==-1&&v==-1)
break;
add(u, v + n, 1);
add(v + n, u, 0);
}
int T=Ek();
if(T == 0) {
cout << "No Solution!" << endl;
return 0;
}
cout << T << endl;
T=n;
for(int i = 1; i <= T; i++)
if(ansk[i] != 0)
cout << i << ' ' << ansk[i] - n << endl;
return 0;
}
匈牙利AC 模板
using namespace std;
int G[maxn][maxn], used[maxn], vis[maxn], n, m;
bool Find(int u) {
for(int i = 1 ; i <= m ; i++) {
if(!vis[i] && G[u][i]) {
///vis[i]表示i男生还没有被别的女生选走
vis[i] = 1;
if(!used[i] || Find(used[i])) {
///如果女生used[i]没有选男生i作伴或者女生used[i]选了男生i,她放弃男生i并且另外找到了自己的伴
///当前还可以挪出来位置
used[i] = u;///就让男生i与女生u作伴
return true;
}
}
}
return false;
}///该函数判断女生能不能找到伴
int main() {
int k, i, a, b, ans;
cin >> n >> m; ///n 女生 m 男生
ans = 0;
mem(G, 0);
while(1) {
cin >> a >> b;
if(a == -1 && b == -1)
break;
G[a][b] = 1;///G[a][b]表示女生a愿意与男生b作伴
}///used[i]表示i男生与used[i]女生作伴
mem(used, 0);
for(i = 1 ; i <= n ; i++) {
mem(vis, 0);
if(Find(i))
ans++;
}
if(ans == 0)
cout << "No Solution!" << endl;
else {
cout << ans << endl;
for(int i = n; i <= m; i++)
if(used[i])
cout << used[i] << ' ' << i << endl;
}
return 0;
}