嗯~第一次写费用流题。。。
这道就是费用流的模板题,找不到更裸的题了
建图:每个m(Man)作为源点,每个H(House)作为汇点,各个源点与汇点分别连一条边,这条边的流量是1(因为每个源点只能走一条边到汇点),费用是 从源点走到汇点的步数,因为有多个源点与汇点,要建一个超级源点与超级汇点,超级源点与各个源点连一条流量为1,费用为0(要避免产生多余的费用)的边
按照这个图跑一发费用流即可
把代码挂上去,用的是前向星写的
1 #include<cstdio> 2 #include<cstring> 3 #include<cmath> 4 #include<iostream> 5 #include<algorithm> 6 #include<set> 7 #include<map> 8 #include<stack> 9 #include<vector> 10 #include<queue> 11 #include<string> 12 #include<sstream> 13 #define MAXN 3000 14 #define MAXM 50000 15 #define INF (1<<30) 16 #define eps 0.000001 17 #define ALL(x) x.begin(),x.end() 18 #define INS(x) inserter(x,x.begin()) 19 using namespace std; 20 int i,j,k,n,m,x,y,T,num,w,Man,House,hou[305][2],man[305][2]; 21 int head[MAXN],vis[MAXN],dis[MAXN],pos[MAXN],Edge,size; 22 char s[305][305]; 23 struct edgenode 24 { 25 int to,next,w,cost; 26 } edge[MAXM]; 27 28 void add_edge(int x,int y,int w,int cost) 29 { 30 edge[Edge].to=y; 31 edge[Edge].w=w; 32 edge[Edge].cost=cost; 33 edge[Edge].next=head[x]; 34 head[x]=Edge; 35 Edge++; 36 37 38 edge[Edge].to=x; 39 edge[Edge].w=0; 40 edge[Edge].cost=-cost; 41 edge[Edge].next=head[y]; 42 head[y]=Edge; 43 Edge++; 44 } 45 46 bool SPFA(int s, int t) 47 { 48 int u,v,i; 49 queue <int> q; 50 memset(vis,0,sizeof(vis)); 51 for(i=0;i<size;i++) dis[i]=INF; 52 dis[s]=0; 53 vis[s]=1; 54 q.push(s); 55 while(!q.empty()) 56 { 57 u=q.front(); q.pop(); vis[u]=0; 58 for (i=head[u];i!=-1;i=edge[i].next) 59 { 60 v=edge[i].to; 61 if(edge[i].w>0&&dis[u]+edge[i].cost<dis[v]) 62 { 63 dis[v]=dis[u]+edge[i].cost; 64 pos[v]=i; 65 if(!vis[v]) 66 { 67 vis[v]=1; 68 q.push(v); 69 } 70 } 71 } 72 } 73 return dis[t]!=INF; 74 } 75 int MinCostFlow(int s,int t) 76 { 77 int i,cost=0,flow=0; 78 while(SPFA(s,t)) 79 { 80 int d=INF; 81 for (i=t;i!=s;i=edge[pos[i]^1].to) 82 { 83 d=min(d,edge[pos[i]].w); 84 } 85 for(i=t;i!=s;i=edge[pos[i]^1].to) 86 { 87 edge[pos[i]].w-=d; 88 edge[pos[i]^1].w+=d; 89 } 90 flow+=d; 91 cost+=dis[t]*d; 92 } 93 return cost; // flow是最大流值 94 } 95 96 int main() 97 { 98 while(scanf("%d%d",&n,&m),n+m) 99 { 100 memset(head,-1,sizeof(head)); 101 Edge=Man=House=num=0; 102 for (i=0;i<n;i++) scanf("%s",s[i]); 103 for (i=0;i<n;i++) 104 { 105 for (j=0;j<m;j++) 106 { 107 if (s[i][j]==‘m‘) 108 { 109 Man++; 110 man[Man][0]=i; 111 man[Man][1]=j; 112 }else 113 if (s[i][j]==‘H‘) 114 { 115 House++; 116 hou[House][0]=i; 117 hou[House][1]=j; 118 } 119 } 120 } 121 size=Man+House+2; 122 /*超级源点0,到各个人的边*/ 123 for (i=1;i<=Man;i++) 124 { 125 add_edge(0,i,1,0); 126 } 127 /*各源点与各汇点之间的边*/ 128 for (i=1;i<=Man;i++) 129 { 130 for (j=1;j<=House;j++) 131 { 132 add_edge(i,Man+j,1,abs(man[i][0]-hou[j][0])+abs(man[i][1]-hou[j][1])); 133 } 134 } 135 /*超级汇点0,到各个人的边*/ 136 for (i=1;i<=House;i++) 137 { 138 add_edge(Man+i,Man+House+1,1,0); 139 } 140 printf("%d\n",MinCostFlow(0,Man+House+1)); 141 } 142 return 0; 143 }
据说可以用KM算法来写,下次补上KM算法的代码。。。
时间: 2024-09-29 10:20:38