網路流之最小費用最大流
阿新 • • 發佈:2018-12-17
具體思路:建好圖之後,每一次從源點到匯點走最短路,如果能走到就加上,如果走不到就停止。具體注意細節在程式碼中解釋。
AC程式碼:
#include<iostream> #include<string> #include<cstring> #include<iomanip> #include<cmath> #include<vector> #include<map> #include<queue> #include<stack> #include<stdio.h> #include<algorithm> using namespace std; # define inf 0x3f3f3f3f # define ll long long # define maxn 100000+10 struct point { int x,y; } H[maxn],M[maxn]; char str[100][100]; int head[maxn];//前向星的建立。 int num; int pree[maxn];//記錄該點前一個連的點。 int prev[maxn];//記錄該點位於前向星的哪一條邊上。 int vis[maxn]; int dist[maxn];//記錄距離 struct node { int to; int w; int cost; int nex; } edge[maxn]; void addage(int fr,int to,int w,int cost) { edge[num].to=to; edge[num].w=w; edge[num].cost=cost; edge[num].nex=head[fr]; head[fr]=num++; edge[num].to=fr;//反向邊的建立,方向相反,流量為0,話費為原來花費的負數。 edge[num].w=0; edge[num].cost=-cost; edge[num].nex=head[to]; head[to]=num++; } bool spfa(int st,int ed) { memset(vis,0,sizeof(vis)); memset(dist,inf,sizeof(dist)); memset(pree,-1,sizeof(pree)); queue<int>q; vis[st]=1; dist[st]=0; q.push(st); while(!q.empty()) { int top=q.front(); q.pop(); vis[top]=0; for(int i=head[top]; i!=-1; i=edge[i].nex) { int temp=edge[i].to; if(edge[i].w>0&&dist[temp]>dist[top]+edge[i].cost)//求最短路的過程,注意dist數組裡存的是花費,不是流量。 { dist[temp]=dist[top]+edge[i].cost; pree[temp]=top; prev[temp]=i; if(vis[temp]==0) { vis[temp]=1; q.push(temp); } } } } return pree[ed]!=-1; } int mincostflow(int st,int ed) { int ans=0; while(spfa(st,ed)) { int minn=inf; for(int i=ed; i!=st; i=pree[i]) { minn=min(minn,edge[prev[i]].w); } ans+=dist[ed]*minn; for(int i=ed; i!=st; i=pree[i]) { edge[prev[i]].w-=minn; edge[prev[i]^1].w+=minn; } } return ans; } int main() { int n,m; while(~scanf("%d%d",&n,&m)&&(m+n)) { num=0; memset(head,-1,sizeof(head)); for(int i=1; i<=n; i++) { scanf("%s",str[i]+1); } int t1=0,t2=0; for(int i=1; i<=n; i++) { for(int j=1; j<=m; j++) { if(str[i][j]=='H') { H[++t1].x=i; H[t1].y=j; } else if(str[i][j]=='m') { M[++t2].x=i; M[t2].y=j; } } } for(int i=1; i<=t1; i++) { for(int j=1; j<=t1; j++) { addage(i,t1+j,1,abs(M[i].x-H[j].x)+abs(M[i].y-H[j].y)); } } int st=0,ed=t1+t1+1; for(int i=1; i<=t1; i++) { addage(st,i,1,0);//源點到學生流量為1,花費為0 } for(int i=1; i<=t1; i++) { addage(t1+i,ed,1,0);//同理 } int ans=mincostflow(st,ed); printf("%d\n",ans); } return 0; }