有个明显的关系:处理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; }