Going Home
生活随笔
收集整理的這篇文章主要介紹了
Going Home
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
http://acm.hdu.edu.cn/showproblem.php?pid=1533
http://poj.org/problem?id=2195
C++版本一
題解:最小費用最大流
/* *@Author: STZG *@Language: C++ */ #include <bits/stdc++.h> #include<iostream> #include<algorithm> #include<cstdlib> #include<cstring> #include<cstdio> #include<string> #include<vector> #include<bitset> #include<queue> #include<deque> #include<stack> #include<cmath> #include<list> #include<map> #include<set> //#define DEBUG #define RI register int #define endl "\n" using namespace std; typedef long long ll; //typedef __int128 lll; const int N=200+10; const int M=100+10; const int MOD=1e9+7; const double PI = acos(-1.0); const double EXP = 1E-8; const int INF = 0x3f3f3f3f; int s,t,n,m,k,p,l,r,u,v; int ans,cnth,cntm,flag,temp,sum,minz,maxflow; int dis[N]; bool vis[N]; char str[N][N]; struct Node{int x,y;Node(){};Node(int X,int Y):x(X),y(Y){} }home[N],man[N]; struct node{int u,v,c,w;node(){};node(int form,int to,int cap,int w):u(form),v(to),c(cap),w(w){} }; vector<node>edge; vector<int> G[N]; void Addedge(int u,int v,int cap,int w){edge.push_back({u,v,cap,w});edge.push_back({v,u,0,-w});int sz=edge.size();G[u].push_back(sz-2);G[v].push_back(sz-1); } bool bfs(int u){//memset(dis,-1,sizeof(dis));for(int i=0;i<=t;i++)dis[i]=INF,vis[i]=0;dis[u]=0;queue<int>q;q.push(u);vis[u]=1;while(!q.empty()){int u=q.front();q.pop();vis[u]=0;for(int i=0;i<G[u].size();i++){node e=edge[G[u][i]];//cout<<u<<" "<<e.v<<endl;if(dis[e.v]>dis[u]+e.w&&e.c>0){dis[e.v]=dis[u]+e.w;if(!vis[e.v]){vis[e.v]=1;q.push(e.v);}}}}return dis[t]!=INF; } int dfs(int u,int flow){vis[u]=1;if(u==t)return flow;int now;for(int i=0;i<G[u].size();i++){node e=edge[G[u][i]];//cout<<ans<<endl;if((!vis[e.v]||e.v==t)&&e.c>0&&dis[u]+e.w==dis[e.v]&&(now=dfs(e.v,min(flow,e.c)))){ans+=e.w*now;//cout<<now<<endl;edge[G[u][i]].c-=now;edge[G[u][i]^1].c+=now;return now;}}return 0; } void dinic(){while(bfs(s)){int res=0;//memset(vis,0,sizeof(vis));while((res=dfs(s,INF))){maxflow+=res;memset(vis,0,sizeof(vis));}} } void init(){for(int i=0;i<=t;i++)G[i].clear();edge.clear();ans=0;maxflow=0; } int main() { #ifdef DEBUGfreopen("input.in", "r", stdin);//freopen("output.out", "w", stdout); #endif//ios::sync_with_stdio(false);//cin.tie(0);//cout.tie(0);//scanf("%d",&t);while(~scanf("%d%d",&n,&m)&&n+m){cnth=cntm=0;for(int i=1;i<=n;i++){scanf("%s",str[i]+1);for(int j=1;j<=m;j++){if(str[i][j]=='H')home[++cnth]=Node(i,j);if(str[i][j]=='m')man[++cntm]=Node(i,j);}}s=0;t=cnth+cntm+1;init();for(int i = 1; i <= cnth; i++){//建圖for(int j = 1; j <= cntm; j++){int dist= abs(home[i].x - man[j].x) + abs(home[i].y - man[j].y);Addedge(i,j+cnth,1,dist);//Addedge(j+cnth,i,0,-dist);}}for(int i=1;i<=cnth;i++){Addedge(s,i,1,0);//Addedge(i,s,0,0);}for(int i=cnth+1;i<t;i++){//Addedge(t,i,0,0);Addedge(i,t,1,0);}//cout<<s<<" "<<t<<endl;dinic();cout<<ans<<endl;}#ifdef DEBUGprintf("Time cost : %lf s\n",(double)clock()/CLOCKS_PER_SEC); #endif//cout << "Hello world!" << endl;return 0; }C++版本二
題解:帶權二分圖的最優匹配
每個man和house建立帶權二分圖,曼哈頓距離就是邊的值,這里要求最小費用,也就是二分圖最小權值匹配,但是KM算法求的是二分圖最大權值匹配,所以此處用邊的負數求最優匹配,求出來的答案的負數就是最小權匹配。
注意:題目說house最多100,但是沒有說明man的范圍,所以man應該最多100*100。
應該用house為二分圖的X部,因為算法復雜度和X部點數有關,所以用點數少的house為X部
因為存的是負數,在預處理X部的頂標值初始化應該是-INF,不能是0
參考文章:KM算法?
/* *@Author: STZG *@Language: C++ */ #include <bits/stdc++.h> #include<iostream> #include<algorithm> #include<cstdlib> #include<cstring> #include<cstdio> #include<string> #include<vector> #include<bitset> #include<queue> #include<deque> #include<stack> #include<cmath> #include<list> #include<map> #include<set> //#define DEBUG #define RI register int #define endl "\n" using namespace std; typedef long long ll; //typedef __int128 lll; const int N=100+10; const int M=100+10; const int MOD=1e9+7; const double PI = acos(-1.0); const double EXP = 1E-8; const int INF = 0x3f3f3f3f; int t,n,m,k,p,l,r,u,v; int ans,cnth,cntm,flag,temp,sum,minz; int Map[N][N],cx[N],cy[N],wx[N],wy[N]; bool visx[N],visy[N]; char str[N][N]; struct node{int x,y;node(){};node(int X,int Y):x(X),y(Y){} }home[M],man[M]; void init(){cnth=0;cntm=0;ans=0; } bool dfs(int u){visx[u]=1;for(int v=1;v<=cntm;v++){if(!visy[v]){int t=wx[u]+wy[v]-Map[u][v];if(t==0){visy[v]=1;if(cy[v]==-1||dfs(cy[v])){cx[u]=v;cy[v]=u;return 1;}}else if(t>0)minz=min(minz,t);}}return 0; } int KM(){memset(cx,-1,sizeof(cx));memset(cy,-1,sizeof(cy));memset(wx,-INF,sizeof(wx));memset(wy,0,sizeof(wy));for(int i = 1; i <= cnth; i++){//建圖for(int j = 1; j <= cntm; j++){wx[i]=max(wx[i],Map[i][j]);}}for(int i=1;i<=cnth;i++){while(1){minz=INF;memset(visx, 0, sizeof(visx));memset(visy, 0, sizeof(visy));if(dfs(i))break;for(int j = 1; j <= cnth; j++)if(visx[j])wx[j] -= minz;for(int j = 1; j <= cntm; j++)if(visy[j])wy[j] += minz;}}int res=0;for(int i=1;i<=cnth;i++)if(cx[i]!=-1)res+=Map[i][cx[i]];return res; } int main() { #ifdef DEBUGfreopen("input.in", "r", stdin);//freopen("output.out", "w", stdout); #endif//ios::sync_with_stdio(false);//cin.tie(0);//cout.tie(0);//scanf("%d",&t);while(~scanf("%d%d",&n,&m)&&n+m){init();for(int i=1;i<=n;i++){scanf("%s",str[i]+1);for(int j=1;j<=m;j++){if(str[i][j]=='H')home[++cnth]=node(i,j);if(str[i][j]=='m')man[++cntm]=node(i,j);}}for(int i = 1; i <= cnth; i++){//建圖for(int j = 1; j <= cntm; j++){Map[i][j] = -abs(home[i].x - man[j].x) - abs(home[i].y - man[j].y);}}cout<<(-KM())<<endl;}#ifdef DEBUGprintf("Time cost : %lf s\n",(double)clock()/CLOCKS_PER_SEC); #endif//cout << "Hello world!" << endl;return 0; }C++版本三
題解:最小費用最大流
#include<bits/stdc++.h> #define ll long long #define pb push_back #define INF 0x3f3f3f3f #define FI first #define SE second #define MP make_pair #define PI pair<int,int> #define lson l,m,rt<<1,ls,rs #define rson m+1,r,rt<<1|1,ls,rs #define test printf("here!!!\n") using namespace std; const int mx=100+10;//最大流的情況下使他最小費用 int n,m; char s[mx]; int st_p,to_p; struct EG {int to;int c;int w;int nxt; }edge[mx*mx*2]; int head[mx*2]; int cnt=1; int dis[mx*2]; int vis[mx*2]; struct Nd {int x,y; }hs[mx],ms[mx]; int tot,tot2; int ans; //int maxflow; void add(int st,int to,int c,int w) {edge[++cnt].to=to;edge[cnt].c=c;edge[cnt].w=w;edge[cnt].nxt=head[st];head[st]=cnt; } int Dinic_SPFA() {for (int i=0;i<=tot+tot2+1;++i) dis[i]=INF,vis[i]=0;queue<int>q;q.push(st_p);vis[st_p]=1;dis[st_p]=0;while (!q.empty()){int u=q.front();q.pop();vis[u]=0;for (int i=head[u];i;i=edge[i].nxt){int v=edge[i].to;if (dis[v]>dis[u]+edge[i].w&&edge[i].c){dis[v]=dis[u]+edge[i].w;if (!vis[v]){q.push(v);vis[v]=1;}}}}return dis[to_p]!=INF; }//判斷有無增廣路,并構造最短邊權的增廣路,同BFS int Dinic_dfs(int u,int flow) {vis[u]=1;if (u==to_p){//maxflow+=flow;return flow;}int used=0;for (int i=head[u];i;i=edge[i].nxt){int v=edge[i].to;if ((!vis[v]||v==to_p)&&dis[v]==dis[u]+edge[i].w&&edge[i].c)//防止0邊權導致的環{int rflow=Dinic_dfs(v,min(flow-used,edge[i].c));if (rflow){used+=rflow;ans+=edge[i].w*rflow;edge[i].c-=rflow;edge[i^1].c+=rflow;if (flow==used) break;}}}return used; } int Dinic() {while (Dinic_SPFA()){vis[to_p]=1;while (vis[to_p]){memset(vis,0,sizeof(vis));Dinic_dfs(st_p,INT_MAX);}} } int main() {while (~scanf("%d%d",&n,&m)&&n+m){memset(head,0,sizeof(head));cnt=1;tot=tot2=0;ans=0;//maxflow=0;for (int i=1;i<=n;++i){scanf("%s",s);for (int j=0;j<m;++j){if (s[j]=='m') ms[++tot].x=i,ms[tot].y=j;else if (s[j]=='H') hs[++tot2].x=i,hs[tot2].y=j;}}for (int i=1;i<=tot;++i){for (int j=1;j<=tot2;++j){int disct=abs(ms[i].x-hs[j].x)+abs(ms[i].y-hs[j].y);add(i,tot+j,1,disct);add(tot+j,i,0,-disct);}}st_p=0;to_p=tot+tot2+1;for (int i=1;i<=tot;++i){add(st_p,i,1,0);add(i,st_p,0,0);}for (int i=tot+1;i<to_p;++i){add(i,to_p,1,0);add(to_p,i,0,0);}Dinic();printf("%d\n",ans);} }?
總結
以上是生活随笔為你收集整理的Going Home的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CCPC2019-湖南全国邀请赛(湘潭大
- 下一篇: Build Tree