集训的图论都快结束了,我才看懂了最小费用流,惭愧啊。 = = 但是今天机械键盘到了,有弄好了自行车,好高兴(^o^)/~
其实也不是看懂,就会套个模板而已。。。。
这题最重要的就是一个:
多组输入一定要写个init()函数清空,并且输入的时候每次都要调用init()
#include <map> #include <set> #include <list> #include <cmath> #include <queue> #include <stack> #include <vector> #include <cstdio> #include <string> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int INF=0x3f3f3f3f; typedef long long LL; #define PI(A) printf("%d ",A) #define SI(N) scanf("%d",&(N)) #define SII(N,M) scanf("%d%d",&(N),&(M)) #define cle(a,val) memset(a,(val),sizeof(a)) #define rep(i,b) for(int i=0;i<(b);i++) #define Rep(i,a,b) for(int i=(a);i<=(b);i++) #define reRep(i,a,b) for(int i=(a);i>=(b);i--) const double EPS= 1e-9 ; /* ///////////////////////// C o d i n g S p a c e ///////////////////////// */ const int MAX_V= 300 + 5 ; ///小白书模板///////////////// ///PS:V(即顶点数)一定要赋值 ///PS:以下多组输入,要初始化 struct edge { int to,cap,cost,rev; }; int V; //顶点数 vector<edge> G[MAX_V];//图的邻接表 int dist[MAX_V]; //最短距离 int prevv[MAX_V],preve[MAX_V]; //最短路中的前驱节点和对应的边 //添加边和费用 void add_edge(int from,int to,int cap,int cost) { G[from].push_back((edge) { to,cap,cost,G[to].size() }); G[to].push_back((edge) { from,0,-cost,G[from].size()-1 }); } //求解从s到t流量为f的最小费用流 //如果不能再增广就返回-1 int min_cost_flow(int s,int t,int f) { int res=0; while(f>0) { fill(dist,dist+V+1,INF); dist[s]=0; bool updata=true; while(updata) { updata=false; for (int v=0; v<V; v++) { if (dist[v]==INF) continue; for(int i=0; i<G[v].size(); i++) { edge &e=G[v][i]; if (e.cap>0&&dist[e.to]>dist[v]+e.cost) { dist[e.to]=dist[v]+e.cost; prevv[e.to]=v; preve[e.to]=i; updata=true; } } } } if (dist[t]==INF) { //不能在增广 return -1; } int d=f; for (int v=t; v!=s; v=prevv[v]) { d=min(d,G[prevv[v]][preve[v]].cap); } f-=d; res+=d*dist[t]; for (int v=t; v!=s; v=prevv[v]) { edge &e=G[prevv[v]][preve[v]]; e.cap-=d; G[v][e.rev].cap+=d; } } return res; } ///end///////////////// char ditu[MAX_V][MAX_V]; int N,M; int main() { #ifndef ONLINE_JUDGE freopen("C:\Users\Zmy\Desktop\in.txt","r",stdin); // freopen("C:\Users\Zmy\Desktop\out.txt","w",stdout); #endif while(~SII(N,M),N||M) { cle(ditu,0); rep(i,N) { scanf("%s",ditu[i]); } int numm=0; rep(i,N) rep(j,M) if (ditu[i][j]=='m') { numm++; } int cntm=1,cntH=numm+1; rep(i,N) { rep(j,M) { if (ditu[i][j]=='m') { cntH=numm+1; rep(i2,N) { rep(j2,M) { if (ditu[i2][j2]=='H') { add_edge(cntm,cntH,1,abs(i-i2)+abs(j-j2)); // printf("cntm=%d cntH=%d ",cntm,cntH); // printf("cost=%d ",abs(i-i2)+abs(j-j2)); cntH++; } } } cntm++; } } } for (int i=1;i<cntm;i++) { add_edge(0,i,1,0); // printf("0->%d ",i); } for (int i=numm+1;i<=2*numm;i++) { add_edge(i,2*numm+1,1,0); // printf("%d->%d ",i,2*numm+1); }
//这的V一定要赋值 V=2*numm+1;
/**< 一定要初始化 */ cle(prevv,0); cle(preve,0); int ans=min_cost_flow(0,2*numm+1,numm); PI(ans); /**< 一定要初始化 以后就用一个init都初始化了*/ for (int i=0;i<MAX_V;i++) { G[i].clear(); } } return 0; }