POJ-2195 Flujo de tarifa de regreso a casa + BFS

Enlace de tema

https://vjudge.net/problem/POJ-2195

Título

Dada una cuadrícula de n * m, hay varios villanos y casas en el medio, y el villano da un paso para gastar 1 RMB, y todos los villanos deben estar en casa (no hay una relación correspondiente entre los villanos) y el costo mínimo

Ideas

A primera vista, pensé que era el camino más corto, pero como no hay correspondencia entre el villano y la casa, es decir, un villano que elige una casa diferente afectará a otros villanos, por lo que el camino directo más corto es definitivamente wa.

Debido a que cada villano tiene que volver a una casa, busque el costo mínimo sobre esta base. Por lo tanto, se puede configurar el flujo de costos. El punto de superfuente conecta al villano con el borde derecho 1, y la casa se conecta al punto de encuentro con el borde derecho 1. Luego se puede establecer la relación villano-casa. El flujo de costos es la condición de flujo máximo (todos tienen una habitación). El costo mínimo de vida) es la respuesta.

Para la conexión específica entre villano y casa, simplemente recorra la imagen completa y ejecute bfs para cada villano.

Código

#include<cstdio>
#include<iostream>
#include<iomanip>
#include<map>
#include<string>
#include<queue>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib> 
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
//#define int long long
using namespace std;
	typedef long long ll;
	const int maxn=205;
	const int maxe=30005;
	const int inf=0x3f3f3f3f;
	int n,m,s,t,cnt;
	int gh[maxn][maxn]; 
	int head[maxn];
	struct Edge{
    
    
		int v,w,next,flow;
	}edge[maxe];
	
	int dis[maxn],incf[maxn],pre[maxn];//incf最小流量 
	bool inque[maxn];
	int maxflow,mincost;
	
	//费用流模版 
	void init(){
    
    
		memset(head,-1,sizeof(head));
		maxflow=mincost=0;
		cnt=0;
	}
	void add(int u,int v,int flow,int cost){
    
    
		//cout<<u<<" "<<v<<" "<<flow<<" "<<cost<<endl;
		edge[cnt].w=cost;
		edge[cnt].v=v;
		edge[cnt].flow=flow;
		edge[cnt].next=head[u];
		head[u]=cnt++;
		return ;
	}
	bool spfa(){
    
    
		queue<int>q;
		memset(dis,0x3f,sizeof(dis));
		memset(inque,0,sizeof(inque));
		q.push(s); dis[s]=0; inque[s]=1; incf[s]=inf;
		while(q.size()){
    
    
			int u=q.front();q.pop();
			inque[u]=0;
			for(int i=head[u];~i;i=edge[i].next){
    
    
				if(!edge[i].flow)	continue;
				int v=edge[i].v;
				if(dis[v]>dis[u]+edge[i].w){
    
    
					dis[v]=dis[u]+edge[i].w;
					incf[v]=min(incf[u],edge[i].flow);
					pre[v]=i;
					if(!inque[v]){
    
    
						q.push(v);
						inque[v]=1;
					}
				}
			}
		}
		if(dis[t]==inf) return 0;
		return 1;
	}
	void MCMF(){
    
    
		while(spfa()){
    
    
			int x=t;
			maxflow+=incf[t];
			mincost+=dis[t]*incf[t];
			int i;
			while(x!=s){
    
    
				i=pre[x];
				edge[i].flow-=incf[t];
				edge[i^1].flow+=incf[t];
				x=edge[i^1].v;
			}
		}
	}
	
	//bfs建图 
	int dxy[][2]={
    
    {
    
    1,0},{
    
    -1,0},{
    
    0,1},{
    
    0,-1}};
	bool vis[maxn][maxn];
	int dis_bfs[maxn][maxn];
	
	inline bool ju(int x,int y){
    
    
		if(x<1||x>n||y<1||y>m||vis[x][y])
			return 0;
		return 1;
	}
	
	void find(int x,int y){
    
    
		memset(vis,0,sizeof vis);
		queue<pair<int,int> >q;
		pair<int,int>p;
		q.push(make_pair(x,y));
		dis_bfs[x][y]=0;
		vis[x][y]=1;
		while(q.size()){
    
    
			p=q.front(),q.pop();
			//找到了房子,连边 
			if(gh[p.first][p.second]<0){
    
    
				add(gh[x][y],-gh[p.first][p.second]+100,1,dis_bfs[p.first][p.second]);
				add(-gh[p.first][p.second]+100,gh[x][y],0,-dis_bfs[p.first][p.second]);
			}
			for(int i=0;i<4;i++){
    
    
				int tx=p.first+dxy[i][0],ty=p.second+dxy[i][1];
				if(ju(tx,ty)){
    
    
					vis[tx][ty]=1;
					q.push(make_pair(tx,ty));
					dis_bfs[tx][ty]=dis_bfs[p.first][p.second]+1;
				}
			}
		}
	}
	
	int main(){
    
    
		while(scanf("%d%d",&n,&m)==2){
    
    
			if(!n&&!m)
				break;
			s=201,t=202;
			init();
			getchar();
			int cnt1=1,cnt2=-1;//编号 
			for(int i=1;i<=n;i++)
				for(int j=1;j<=m;j++){
    
    
					char ch=getchar();
					while(ch=='\n'||ch==' ')
						ch=getchar();
					if(ch=='.')
						gh[i][j]=0;
					else if(ch=='m')
						gh[i][j]=cnt1++;
					else
						gh[i][j]=cnt2--;
				}
			for(int i=1;i<=n;i++)
				for(int j=1;j<=m;j++)
					if(gh[i][j]>0)
						find(i,j);
			for(int i=1;i<=n;i++)
				for(int j=1;j<=m;j++)
					if(gh[i][j]>0){
    
    //源点-人 
						add(s,gh[i][j],1,0);
						add(gh[i][j],s,0,0);
					}
					else if(gh[i][j]<0){
    
    //房子-汇点 
						add(-gh[i][j]+100,t,1,0);
						add(t,-gh[i][j]+100,0,0);
					}
			MCMF();
			printf("%d\n",mincost);
		}
	}

Supongo que te gusta

Origin blog.csdn.net/TheSunspot/article/details/108262645
Recomendado
Clasificación