有个明显的关系:处理i城市之前必须处理掉i-1城市~~
先floyed求出各点间的距离mp[i][j],
把n个点一分为3(P1i,P2i,P3i),源点S,汇点T,建图如下:
1)S向P11连一条流量为k,费用为零的边:(k个小队)
2)P1i向P1(i+1)连一条流量为k,费用为零的边:(没去i城市的小队可去i+1城市)
2)P1i向P2i连一条流量为1,费用为mp[0][i]的边:(一个小队从0城市出发到了i城市)
3)P2i向T连一条流量为1,费用为mp[i][0]的边:(回到0城市)
4)S向P3i连一条流量为1,费用为零的边:(处理了i城市后的小队还可以去别的城市做任务)
5)P3i向P2j(i<j)连一条流量为1,费用为mp[i][j]-mp[i][0]的边:(去i城市的小队没有直接回去而是又去了j城市)
以上建图方案能满足“处理i城市之前必须处理掉i-1城市”的关系,因为每个小队都是按顺序去的各地~~
代码如下:
#include <cstdio>
#include <stack>
#include <cstring>
#include <iostream>
using namespace std;
const int NN=500;
const int MM=300000;
const int INF=0x3f3f3f3f;
int n,mp[NN][NN];
void floyed()
{
for (int k=0; k<=n; k++)
for (int i=0; i<=n; i++) if (k!=i)
for (int j=0; j<=n; j++) if (k!=j && i!=j)
if (mp[i][k]+mp[k][j]<mp[i][j]) mp[i][j]=mp[i][k]+mp[k][j];
}
int S,s,T,NV,en,head[NN];
struct Edge
{
int u,v,f,c,next;
} e[MM];
void add(int u,int v,int f,int c)
{
e[en].u=u; e[en].v=v; e[en].c=c; e[en].f=f; e[en].next=head[u];
head[u]=en++;
e[en].u=v; e[en].v=u; e[en].c=-c; e[en].f=0; e[en].next=head[v];
head[v]=en++;
}
int dis[NN],fa[NN];
bool vis[NN];
bool spfa()
{
for (int i=0; i<NV; i++) dis[i]=INF;
dis[S]=0;
fa[S]=-1;
stack<int> q;
q.push(S);
while (!q.empty())
{
int u=q.top();
q.pop();
vis[u]=false;
for (int i=head[u]; i!=-1; i=e[i].next)
{
int v=e[i].v;
if (e[i].f && dis[v]>dis[u]+e[i].c)
{
dis[v]=dis[u]+e[i].c;
fa[v]=i;
if (!vis[v])
{
vis[v]=true;
q.push(v);
}
}
}
}
if (dis[T]!=INF) return true;
else return false;
}
int fee_flow()
{
int max_flow=0;
int min_cost=0;
while (spfa())
{
int flow=INF;
int u,v;
for (v=T; fa[v]!=-1; v=u)
{
u=e[fa[v]].u;
if (flow>e[fa[v]].f) flow=e[fa[v]].f;
}
for (v=T; fa[v]!=-1; v=u)
{
u=e[fa[v]].u;
e[fa[v]].f-=flow;
e[fa[v]^1].f+=flow;
}
max_flow+=flow;
min_cost+=dis[T];
}
return min_cost;
}
int p1[NN],p2[NN],p3[NN];
int main()
{
int m,k,u,v,w;
while (scanf("%d%d%d",&n,&m,&k),n|m|k)
{
memset(mp,0x3f,sizeof(mp));
for (int i=1; i<=m; i++)
{
scanf("%d%d%d",&u,&v,&w);
if (mp[u][v]>w) mp[u][v]=mp[v][u]=w;
}
floyed();
memset(head,-1,sizeof(head));
en=S=0; T=3*n+1; NV=T+1;
for (int i=1; i<=n; i++)
{
p1[i]=i;
p2[i]=i+n;
p3[i]=i+2*n;
}
add(S,1,k,0);
for (int i=1; i<n; i++) add(p1[i],p1[i+1],k,0);
for (int i=1; i<=n; i++) add(p1[i],p2[i],1,mp[0][i]);
for (int i=1; i<n; i++) add(S,p3[i],1,0);
for (int i=1; i<=n; i++) add(p2[i],T,1,mp[0][i]);
for (int i=1; i<n; i++)
for (int j=i+1; j<=n; j++) add(p3[i],p2[j],1,mp[i][j]-mp[0][i]);
printf("%d\n",fee_flow());
}
return 0;
}