标签:
动态加点KM
构图:
X 侧点为对菜品的需求,Y 侧点为厨师对菜品的供应
如果让
记
考虑第一次匹配,我们只会让每个厨师最先制作该菜品。
而第二次匹配时,可以通过在Y侧,新增已经匹配的厨师倒数第二次制作菜品的点。
所以我们可以通过每次匹配完一个X侧点之后,新增一个Y侧点,这样就能只建
同类的问题有 bzoj1070
bzoj 1070 的构图
void build()
{
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
for(int k = 1; k <= n; k++)
w[i][m*(k-1)+j] = -fix[i][j]*k;
}
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <vector>
#include <utility>
#include <stack>
#include <queue>
#include <iostream>
#include <algorithm>
template<class Num>void read(Num &x)
{
char c; int flag = 1;
while((c = getchar()) < ‘0‘ || c > ‘9‘)
if(c == ‘-‘) flag *= -1;
x = c - ‘0‘;
while((c = getchar()) >= ‘0‘ && c <= ‘9‘)
x = (x<<3) + (x<<1) + (c-‘0‘);
x *= flag;
return;
}
template<class Num>void write(Num x)
{
if(x < 0) putchar(‘-‘), x = -x;
static char s[20];int sl = 0;
while(x) s[sl++] = x%10 + ‘0‘,x /= 10;
if(!sl) {putchar(‘0‘);return;}
while(sl) putchar(s[--sl]);
}
const int maxp = 805, maxn = 45, maxm = 105, size = maxp*maxm + maxp;
const int INF = 0x3f3f3f3f, Nya = -1;
int n, m, tot, ind, p[maxn];
int cost[maxp][maxm], w[maxp][size];
int set[maxp], cnt[maxm], type[size];
bool visx[maxp], visy[size];
int lnk[size], lx[maxp], ly[size];
int slack;
void add(int t)
{
type[++ind] = t, ++cnt[t];
for(int i = 1; i <= tot; i++)
w[i][ind] = -cnt[t]*cost[set[i]][t];
}
bool find(int a)
{
visx[a] = true;
for(int i = 1; i <= ind; i++)
{
if(visy[i]) continue;
int calc = lx[a] + ly[i] - w[a][i];
if(!calc)
{
visy[i] = true;
if(!lnk[i] || find(lnk[i]))
{
if(!lnk[i]) add(type[i]);
lnk[i] = a;
return true;
}
}
else
slack = std::min(slack, calc);
}
return false;
}
void clear()
{
for(int i = 1; i <= tot; i++) visx[i] = false;
for(int i = 1; i <= ind; i++) visy[i] = false;
}
void init()
{
read(n), read(m);
for(int i = 1; i <= n; i++)
read(p[i]), tot += p[i];
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
read(cost[i][j]);
}
void build()
{
int id = 0;
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= p[i]; j++)
set[id + j] = i;
id += p[i];
}
for(int i = 1; i <= m; i++) add(i);
}
void adjust()
{
for(int i = 1; i <= tot; i++)
if(visx[i]) lx[i] -= slack;
for(int i = 1; i <= ind; i++)
if(visy[i]) ly[i] += slack;
}
int KM()
{
int ret = 0;
for(int i = 1; i <= tot; i++)
{
lx[i] = -INF;
for(int j = 1; j <= ind; j++)
lx[i] = std::max(lx[i], w[i][j]);
}
// lx[i] + ly[j] >= w[i][j]
for(int i = 1; i <= tot; i++)
{
while(true)
{
slack = INF;
clear();
if(find(i)) break;
adjust();
}
}
for(int i = 1; i <= ind; i++)
if(lnk[i]) ret += w[lnk[i]][i];
return -ret;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("bzoj2879.in","r",stdin);
freopen("bzoj2879.out","w",stdout);
#endif
init(), build();
write(KM());
#ifndef ONLINE_JUDGE
fclose(stdin);
fclose(stdout);
#endif
return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:
原文地址:http://blog.csdn.net/cyxhahaha/article/details/47342901