火星探险问题(最大费用最大流)
Posted hsez-cyx
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了火星探险问题(最大费用最大流)相关的知识,希望对你有一定的参考价值。
Solution
容易想到费用流
为解决点权问题,将一个不是障碍的点 i 拆成两个点 ai,bi
从 ai 向 bi 连一条流量为正无穷(表示可以无限次经过),费用为 0(表示这些经过没有收益)的边
若点 i 是石块,则再从 ai 向 bi 连一条流量为1(表示只能经过一次),费用为 1(表示这次经过收益为 1)的边
若点 i 可以到点 j 且 i 和 j 都不是障碍,则从 bi 向 aj 连一条流量为正无穷,费用为 0 的边
从起点向 a1 连一条流量为探测车数,费用为0的边
从 bn 向终点连一条流量为探测车数,费用为0的边
跑最大费用最大流
Code
#include <cstdio> #include <cstdlib> #include <queue> #include <cstring> #include <algorithm> using namespace std; const int N=3e3,M=1e5; int pre[N],s,t,car,d[N],n,m,incf[N],a[40][40],inf=1<<30,dis[N]; int head[N],nxt[M],ver[M],edge[M],cost[M],tot=1,maxflow,maxcost; bool in[N]; int id(int x,int y,int inv) { return (x-1)*m+y+inv*n*m; } void add(int u,int v,int w,int c) { ver[++tot]=v,nxt[tot]=head[u],edge[tot]=w,cost[tot]=c,head[u]=tot; ver[++tot]=u,nxt[tot]=head[v],edge[tot]=0,cost[tot]=-c,head[v]=tot; } bool spfa() { memset(dis,0x80,sizeof(dis)); memset(pre,0,sizeof(pre)); int last=dis[s]; queue <int> q; dis[s]=0,q.push(s),incf[s]=1<<30; while(!q.empty()) { int u=q.front(); q.pop(); in[u]=false; for(int i=head[u],v;i;i=nxt[i]) if(edge[i]>0 && dis[v=ver[i]]<dis[u]+cost[i]) { dis[v]=dis[u]+cost[i]; incf[v]=min(edge[i],incf[u]); pre[v]=i; if(!in[v]) in[v]=true,q.push(v); } } return dis[t]!=last; } void update() { maxflow+=incf[t],maxcost+=incf[t]*dis[t]; int x=t; while(x!=s) { int i=pre[x]; edge[i]-=incf[t],edge[i^1]+=incf[t]; x=ver[i^1]; } } void dfs(int x,int y,int pos,int k) { int kx,ky,mov; for(int i=head[pos];i;i=nxt[i]) { int v=ver[i]; if(v==s || v==t || v==pos-n*m || edge[i^1]<=0) continue; edge[i^1]--; if(v>n*m) { dfs(x,y,v,k); return; } if(v==(x-1)*m+y+1) kx=x,ky=y+1,mov=1; else kx=x+1,ky=y,mov=0; printf("%d %d ",k,mov); dfs(kx,ky,v+n*m,k); return; } } int main() { scanf("%d%d%d",&car,&m,&n); s=0,t=n*m*2+1; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&a[i][j]); if(a[n][m]==1 || a[1][1]==1) return 0; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { if(a[i][j]==1) continue; add(id(i,j,0),id(i,j,1),inf,0); if(a[i][j]==2) add(id(i,j,0),id(i,j,1),1,1); if(i<n && a[i+1][j]!=1) add(id(i,j,1),id(i+1,j,0),inf,0); if(j<m && a[i][j+1]!=1) add(id(i,j,1),id(i,j+1,0),inf,0); } add(s,id(1,1,0),car,0),add(id(n,m,1),t,car,0); while(spfa()) update(); for(int i=1;i<=maxflow;i++) dfs(1,1,1,i); return 0; }
以上是关于火星探险问题(最大费用最大流)的主要内容,如果未能解决你的问题,请参考以下文章