1.多路径最短路用费用流实现
2.每个点要被强制流过->拆点成弧并且加下界为1的容量
3.所有点向比它编号大的点连边
#include <iostream> #include <stdio.h> #include <queue> #include <math.h> #include <string.h> using namespace std; #define V 1500 #define E 1000000 #define inf 0x3F3F3F3F int n,m; int vis[V]; int dist[V]; int pre[V]; #define left(x) (x*2-1) #define right(x) (x*2) int map[V][V]; int s,start,end,super_start,super_end,top; struct Edge{ int u,v,c,cost,next; }edge[E]; int head[V],cnt; void init(){ cnt=0; memset(head,-1,sizeof(head)); } void addedge(int u,int v,int c,int cost){ edge[cnt].u=u;edge[cnt].v=v;edge[cnt].cost=cost; edge[cnt].c=c;edge[cnt].next=head[u];head[u]=cnt++; edge[cnt].u=v;edge[cnt].v=u;edge[cnt].cost=-cost; edge[cnt].c=0;edge[cnt].next=head[v];head[v]=cnt++; } bool spfa(int begin,int end){ int u,v; queue<int> q; for(int i=0;i<=end+2;i++){ pre[i]=-1; vis[i]=0; dist[i]=inf; } vis[begin]=1; dist[begin]=0; q.push(begin); while(!q.empty()){ u=q.front(); q.pop(); vis[u]=0; for(int i=head[u];i!=-1;i=edge[i].next){ if(edge[i].c>0){ v=edge[i].v; if(dist[v]>dist[u]+edge[i].cost){ dist[v]=dist[u]+edge[i].cost; pre[v]=i; if(!vis[v]){ vis[v]=true; q.push(v); } } } } } return dist[end]!=inf; } int MCMF(int begin,int end){ int ans=0,flow; int flow_sum=0; while(spfa(begin,end)){ flow=inf; for(int i=pre[end];i!=-1;i=pre[edge[i].u]) if(edge[i].c<flow) flow=edge[i].c; for(int i=pre[end];i!=-1;i=pre[edge[i].u]){ edge[i].c-=flow; edge[i^1].c+=flow; } ans+=dist[end]; flow_sum+=flow; } return ans; } void build(){ for(int i=0;i<=n;i++) for(int j=0;j<=n;j++) map[i][j]=i==j?0:inf; for(int i=0,a,b,c;i<m;i++){ scanf("%d%d%d",&a,&b,&c); map[a][b]=map[b][a]=min(map[a][b],c); } for(int k=0;k<=n;k++) for(int i=0;i<=n;i++) for(int j=0;j<=n;j++) map[i][j]=min(map[i][j],map[i][k]+map[k][j]); start=0,end=2*n+1,top=end+1; super_start=top+1,super_end=top+2; init(); //每个点要被强制流过->拆点成弧并且加下界为1的容量 for(int i=1;i<=n;i++){ addedge(super_start,right(i),1,0);//加下界为1的容量 addedge(left(i),super_end,1,0);//加下界为1的容量 addedge(start,left(i),inf,map[0][i]); addedge(right(i),end,inf,map[0][i]); } //所有点向比它编号大的点连边 for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) addedge(right(i),left(j),1,map[i][j]); //警察队数 addedge(top,start,s,0); addedge(end,top,inf,0); } int main(){ while(scanf("%d%d%d",&n,&m,&s),n+m+s){ build(); int res=MCMF(super_start,super_end); printf("%d\n",res); } return 0; }