bzoj 2324: [ZJOI2011]营救皮卡丘

时间:2021-01-29 20:09:37
 #include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#define M 1000
#define inf 2139062143
using namespace std;
int cnt=,n,K,m,T,q[*M],d[M],f[M],head[M],next[*M],u[*M],v[*M],w[*M],fro[*M],fr[M],S1,d1[M][M];
int ans;
void jia1(int a1,int a2,int a3,int a4)
{
cnt++;
next[cnt]=head[a1];
head[a1]=cnt;
fro[cnt]=a1;
u[cnt]=a2;
v[cnt]=a3;
w[cnt]=a4;
}
void jia(int a1,int a2,int a3,int a4)
{
jia1(a1,a2,a3,a4);
jia1(a2,a1,,-a4);
return;
}
bool spfa()
{
memset(d,,sizeof(int)*(T+));
d[]=;
f[]=;
q[]=;
int h=,t=;
for(;h<t;)
{
h++;
int p=q[h];
f[p]=;
for(int i=head[p];i;i=next[i])
if(v[i]&&d[u[i]]>d[p]+w[i])
{
d[u[i]]=d[p]+w[i];
fr[u[i]]=i;
if(!f[u[i]])
{
f[u[i]]=;
t++;
q[t]=u[i];
}
}
}
if(d[T]!=inf)
return ;
return ;
}
void mcf()
{
int mx=inf;
for(int i=fr[T];i;i=fr[fro[i]])
mx=min(mx,v[i]);
for(int i=fr[T];i;i=fr[fro[i]])
{
v[i]-=mx;
v[i^]+=mx;
ans+=mx*w[i];
}
return;
}
int gcd(int a1,int a2)
{
int a3=a1%a2;
for(;a3;)
{
a1=a2;
a2=a3;
a3=a1%a2;
}
return a2;
}
int main()
{
scanf("%d%d%d",&n,&m,&K);
S1=*n+;
T=*n+;
memset(d1,,sizeof(d1));
for(int i=;i<=m;i++)
{
int a1,a2,a3;
scanf("%d%d%d",&a1,&a2,&a3);
d1[a1][a2]=min(d1[a1][a2],a3);
d1[a2][a1]=min(d1[a2][a1],a3);
}
for(int k=;k<=n;k++)
for(int i=;i<=n;i++)
for(int j=k;j<=n;j++)
d1[i][j]=min(d1[i][j],d1[i][k]+d1[k][j]);
jia(,S1,K,);
for(int i=;i<=n;i++)
{
jia(S1,n+i,,d1[][i]);
jia(,i,,);
jia(i+n,T,,);
for(int j=i+;j<=n;j++)
jia(i,j+n,,d1[i][j]);
}
for(;spfa();)
mcf();
printf("%d",ans);
return ;
}

先预处理出所有点之间的最短距离,开一个附加源S1,S到S1连一个容量为k的边,拆点S1到每个i2连容量1费用d[0][i],每个i2向T连边,每个i1向比他大的j2建边。费用流。