P6577 【模板】二分图最大权完美匹配
①、进阶指南上说他的KM算法的时间复杂度是O(N3)的,其实分析一下,就可以发现,它的时间复杂度其实是O(N4)的,这题过不去。
只能过去四个点。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
#define llu unsigned ll
using namespace std;
const int inf=0x3f3f3f3f;
const ll lnf=0x3f3f3f3f3f3f3f3f;
const int maxn=510;
ll w[maxn][maxn];
ll la[maxn],lb[maxn];
bool va[maxn],vb[maxn];
int match[maxn],n,m;
ll delta;
bool dfs(int x)
{
va[x]=1;
for(int y=1;y<=n;y++)
{
if(!vb[y])
if(la[x]+lb[y]-w[x][y]==0)
{
vb[y]=1;
if(!match[y]||dfs(match[y]))
{
match[y]=x;
return true;
}
}
else delta = min(delta,la[x]+lb[y]-w[x][y]);
}
return false;
}
ll KM(void)
{
for(int i=1;i<=n;i++)
{
la[i]=-lnf;
lb[i]=0;
for(int j=1;j<=n;j++)
la[i]=max(la[i],w[i][j]);
}
for(int i=1;i<=n;i++)
{
while(true)
{
for(int j=1;j<=n;j++)
{
va[j]=vb[j]=false;
}
delta = lnf;
if(dfs(i)) break;
for(int j=1;j<=n;j++)
{
if(va[j]) la[j]-=delta;
if(vb[j]) lb[j]+=delta;
}
}
}
ll ans=0;
for(int i=1;i<=n;i++)
ans+=w[match[i]][i];
return ans;
}
int main(void)
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
w[i][j]=-lnf;
int x,y,z;
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&z);
w[x][y]=max(w[x][y],1ll*z);
}
printf("%lld\n",KM());
for(int i=1;i<=n;i++)
printf("%lld ",match[i]);
putchar('\n');
return 0;
}
②、之前还存了一个完全图优化的板子,过了五个点,看来有一个是完全图。
不过这两个板子应该都是加算法,最坏情况到了O(N4)
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
#define llu unsigned ll
using namespace std;
const int inf=0x3f3f3f3f;
const ll lnf=0x3f3f3f3f3f3f3f3f;
const int maxn=510;
ll w[maxn][maxn];
ll la[maxn],lb[maxn],d[maxn];
bool va[maxn],vb[maxn];
int match[maxn],n,m;
bool dfs(int x)
{
va[x]=1;
for(int y=1;y<=n;y++)
{
if(!vb[y])
if(la[x]+lb[y]-w[x][y]==0)
{
vb[y]=1;
if(!match[y]||dfs(match[y]))
{
match[y]=x;
return true;
}
}
else d[y] = min(d[y],la[x]+lb[y]-w[x][y]);
}
return false;
}
ll KM(void)
{
for(int i=1;i<=n;i++)
{
la[i]=-lnf;
lb[i]=0;
for(int j=1;j<=n;j++)
la[i]=max(la[i],w[i][j]);
}
for(int i=1;i<=n;i++)
{
while(true)
{
for(int j=1;j<=n;j++)
{
va[j]=vb[j]=false;
d[j]=lnf;
}
if(dfs(i)) break;
ll c=lnf;
for(int j=1;j<=n;j++)
if(!vb[j]) c=min(c,d[j]);
for(int j=1;j<=n;j++)
{
if(va[j]) la[j]-=c;
if(vb[j]) lb[j]+=c;
}
}
}
ll ans=0;
for(int i=1;i<=n;i++)
ans+=w[match[i]][i];
return ans;
}
int main(void)
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
w[i][j]=-lnf;
int x,y,z;
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&z);
w[x][y]=max(w[x][y],1ll*z);
}
printf("%lld\n",KM());
for(int i=1;i<=n;i++)
printf("%lld ",match[i]);
putchar('\n');
return 0;
}
③、于是我们找到了算法复杂度为O(N3)的bfs写法。
其实这个算法在数据随机下是O(N 3),但是可以被卡成O(N4)
但是因为这个题大数据下随机,所以可以通过这个题。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
#define llu unsigned ll
using namespace std;
const int inf=0x3f3f3f3f;
const ll lnf=0x3f3f3f3f3f3f3f3f;
const int maxn=510;
ll w[maxn][maxn];
ll la[maxn],lb[maxn];
ll p[maxn],c[maxn];
bool vb[maxn];
int match[maxn],n,m;
void bfs(int x)
{
int a,y=0,yy=0;
ll d;
for(int i=1;i<=n;i++)
p[i]=0,c[i]=lnf;
match[y]=x;
do{
a=match[y],d=lnf,vb[y]=true;
for(int b=1;b<=n;b++)
{
if(!vb[b])
{
if(c[b]>la[a]+lb[b]-w[a][b])
c[b]=la[a]+lb[b]-w[a][b],p[b]=y;
if(c[b]<d) d=c[b],yy=b;
}
}
for(int b=0;b<=n;b++)
{
if(vb[b]) la[match[b]]-=d,lb[b]+=d;
else c[b]-=d;
}
y=yy;
}while(match[y]);
while(y) match[y]=match[p[y]],y=p[y];
}
ll KM(void)
{
for(int i=1;i<=n;i++)
la[i]=lb[i]=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++) vb[j]=false;
bfs(i);
}
ll ans=0;
for(int i=1;i<=n;i++)
ans+=w[match[i]][i];
return ans;
}
int main(void)
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
w[i][j]=-lnf;
int x,y,z;
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&z);
w[x][y]=max(w[x][y],1ll*z);
}
printf("%lld\n",KM());
for(int i=1;i<=n;i++)
printf("%lld ",match[i]);
putchar('\n');
return 0;
}