把每个点移动到对应位置的总费用最小。建图后费用流。继续水水练练手~
#include<iostream> #include<queue> #include<cstdio> #include<vector> #include<algorithm> using namespace std; const int inf=0x3f3f3f3f; const int MAXN=20005, MAXE=4000000; int e[MAXE][4];int head[MAXN];int nume; int n,m;int N,M; void inline adde(int i,int j,int c,int w) { e[nume][0]=j;e[nume][1]=head[i];head[i]=nume; e[nume][2]=c;e[nume++][3]=w; e[nume][0]=i;e[nume][1]=head[j];head[j]=nume; e[nume][2]=0;e[nume++][3]=-w; } struct point { int x,y; int id; }; int inline getdis(point a,point b) { return abs(a.x-b.x)+abs(a.y-b.y); } vector<point>man,house; void build() { N=man.size();M=house.size(); for(int i=0;i<N;i++) { adde(0,i+1,1,0); for(int j=0;j<M;j++) adde(i+1,j+1+N,1,getdis(man[i],house[j])); } for(int i=0;i<M;i++) adde(i+N+1,N+M+1,1,0); } int inq[MAXN];int prv[MAXN];int pre[MAXN]; int d[MAXN]; bool spfa(int & sum) { for(int i=0;i<=N+M+1;i++) { d[i]=inf; pre[i]=prv[i]=inq[i]=0; } queue<int>q; q.push(0); inq[0]=1; d[0]=0; while(!q.empty()) { int cur=q.front(); q.pop(); inq[cur]=0; for(int j=head[cur];j!=-1;j=e[j][1]) { int to=e[j][0]; if(d[to]>d[cur]+e[j][3]&&e[j][2]>0) { d[to]=d[cur]+e[j][3]; pre[to]=j; prv[to]=cur; if(!inq[to]) { q.push(to); inq[to]=1; } } } } int minf=inf; if(d[N+M+1]==inf)return 0; int cur=N+M+1; while(cur!=0) { minf=min(minf,e[pre[cur]][2]); cur=prv[cur]; } cur=N+M+1; while(cur!=0) { e[pre[cur]][2]-=minf; e[pre[cur]^1][2]+=minf; cur=prv[cur]; } sum+=d[N+M+1]*minf; return 1; } int mincost() { int sum=0; while(spfa(sum)); return sum; } void init() { for(int i=0;i<MAXN-1;i++) { head[i]=-1; } nume=0; man.clear(); house.clear(); } int main() { while(~scanf("%d%d",&n,&m)&&(n||m)) { init(); char t; point p; for(int i=0;i<n;i++) for(int j=0;j<m;j++) { cin>>t; if(t=='m') { p.x=i;p.y=j; p.id=1; man.push_back(p); } else if(t=='H') { p.x=i;p.y=j; p.id=2; house.push_back(p); } } build(); int ans=mincost(); printf("%d\n",ans); } return 0; }
时间: 2024-11-06 03:55:02