hdu 4411(最小权匹配or费用流)

时间:2023-02-03 07:45:54
题意:n个小偷在n个不同城市,某些城市之间有道路连接,k个警察在城市0,问将所有小偷抓好城市0警察所花费的最小总路程,还有一个条件是抓小偷必须按1,2,3,4……n顺序。
思路:可以用最小权匹配来做,抓每个小偷的警察必然是从小偷编号之前的那些城市过来的,所以每个城市能被你比他编号小的城市所匹配。而城市0则可以拆成个点,这k个点可以匹配任意点,也可以被任意点匹配。总体来说相当于将城市路径分解成k个环,求解这k个环的最小长度和。
hdu 4411(最小权匹配or费用流)hdu 4411(最小权匹配or费用流)View Code
费用流
建图:将每个城市拆成出点和人点,两点之间加一条容量为1,费用为-M的边,其中M要尽量大。0点到每个入点连一条容量为1费用为0的边,每个出点到汇点连接一条容量为1费用为零的边。然后0点到汇点连接一条容量为k费用为0的边,源点到0点连接一条费用为0,容量为k的边。跑最小费用最大流,结果加上M*n。
hdu 4411(最小权匹配or费用流)hdu 4411(最小权匹配or费用流)View Code
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<queue>
 7 using namespace std;
 8 #define rep(i,a,b) for(int i=(a);i<=(b);i++)
 9 #define inf 0x3f3f3f3f
10 #define N 505
11 #define M 100010
12 queue<int> q;
13 int cnt,S,T;
14 int net[110][110],pre[N],low[N],dist[N],p[N];
15 struct edge{
16     int u,v,cap,cost,next;
17 }e[M];
18 void addedge(int u,int v,int cap,int cost){
19     e[cnt].u=u,e[cnt].v=v,e[cnt].cap=cap,e[cnt].cost=cost,e[cnt].next=pre[u],pre[u]=cnt++;
20     e[cnt].u=v,e[cnt].v=u,e[cnt].cap=0,e[cnt].cost=-cost,e[cnt].next=pre[v],pre[v]=cnt++;
21 }
22 bool spfa(){
23     memset(dist,0x3f3f,sizeof(dist));
24     memset(low,0,sizeof(low));
25     memset(p,-1,sizeof(p));
26     low[S]=inf;
27     dist[S]=0;q.push(S);
28     while(!q.empty()){
29 
30         int u=q.front();q.pop();
31         for(int edg=pre[u];edg!=-1;edg=e[edg].next){
32             int v=e[edg].v;
33             if(e[edg].cap>0&&dist[v]>dist[u]+e[edg].cost){
34                 dist[v]=dist[u]+e[edg].cost;
35                 q.push(v);
36                 low[v]=min(e[edg].cap,low[u]);
37                 p[v]=edg;
38             }
39         }
40     }
41     return low[T]!=0;
42 }
43 int flowcost(){
44     int ret=0;
45     while(spfa()){
46         ret+=low[T]*dist[T];
47         for(int t=p[T];t!=-1;t=p[e[t].u]){
48             e[t].cap-=low[T];
49             e[t^1].cap+=low[T];
50         }
51     }
52     return ret;
53 }
54 int main(){
55     int n,m,k;
56     while(scanf("%d%d%d",&n,&m,&k),n||m||k){
57         memset(pre,-1,sizeof(pre));
58         cnt=0;
59         T=2*n+1;S=T+1;
60         memset(net,0x3f3f,sizeof(net));
61         for(int i=1;i<=m;i++){
62             int u,v,w;
63             scanf("%d%d%d",&u,&v,&w);
64             net[u][v]=net[v][u]=min(w,net[v][u]);
65         }
66         rep(h,0,n)rep(i,0,n)rep(j,0,n){
67             net[i][j]=min(net[i][j],net[i][h]+net[h][j]);
68         }
69         addedge(S,0,k,0);
70         addedge(0,T,k,0);
71         rep(i,1,n){
72             rep(j,1,n){
73                 if(i<j){
74                     addedge(i+n,j,1,net[i][j]);
75                 }
76             }
77             addedge(0,i,1,net[0][i]);
78             addedge(i+n,T,1,net[i][0]);
79             addedge(i,i+n,1,-1000000);
80         }
81         printf("%d\n",flowcost()+n*1000000);
82     }
83     return 0;
84 }