洛谷P3356 火星探险问题(费用流)

时间:2022-01-10 12:47:09

传送门

深海机器人问题差不多……看到有的大佬是用dp过的,强无敌……

考虑一下,把每一个点拆点,分别是$A_i$和$B_i$,连一条容量为$inf$,费用为$0$的边,表示可以随便走。如果有石头,再连一条边,容量为$1$,费用为$1$,表示只能走一次,且有$1$的价值。然后套路的建一个超级源和超级汇之后跑一个最大费用流即可

至于如何输出方案,可以一遍$dfs$,每一次只选一条边,然后判断一下这条边被选的次数是否大于等于反向边的流量,如果是说明已经不能再选,然后去选别的边

 //minamoto
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define inf 0x3f3f3f3f
using namespace std;
#define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[<<],*p1=buf,*p2=buf;
inline int read(){
#define num ch-'0'
char ch;bool flag=;int res;
while(!isdigit(ch=getc()))
(ch=='-')&&(flag=true);
for(res=num;isdigit(ch=getc());res=res*+num);
(flag)&&(res=-res);
#undef num
return res;
}
char sr[<<],z[];int C=-,Z;
inline void Ot(){fwrite(sr,,C+,stdout),C=-;}
inline void print(int x){
if(C><<)Ot();
while(z[++Z]=x%+,x/=);
while(sr[++C]=z[Z],--Z);
}
const int N=,M=;
int ver[M],Next[M],head[N],edge[M],flow[M],tmp[M],tot=;
int dis[N],disf[N],Pre[N],last[N],vis[N],maxflow=;
int ans[N],m=;
int id[][],mp[][];
int n,p,q,s,t,num=;
queue<int> Q;
inline void add(int u,int v,int f,int e){
ver[++tot]=v,Next[tot]=head[u],head[u]=tot,flow[tot]=f,edge[tot]=e;
ver[++tot]=u,Next[tot]=head[v],head[v]=tot,flow[tot]=,edge[tot]=-e;
}
bool spfa(){
memset(dis,0xef,sizeof(dis));
Q.push(s),dis[s]=,disf[s]=inf,Pre[t]=-;
while(!Q.empty()){
int u=Q.front();Q.pop();vis[u]=;
for(int i=head[u];i;i=Next[i]){
int v=ver[i];
if(flow[i]&&dis[v]<dis[u]+edge[i]){
dis[v]=dis[u]+edge[i],last[v]=i,Pre[v]=u;
disf[v]=min(disf[u],flow[i]);
if(!vis[v]) vis[v]=,Q.push(v);
}
}
}
return ~Pre[t];
}
void dinic(){
while(spfa()){
int u=t;maxflow+=disf[t];
while(u!=s){
flow[last[u]]-=disf[t];
flow[last[u]^]+=disf[t];
u=Pre[u];
}
}
}
void dfs(int x,int y){
int now=id[x][y],d0=id[x+][y],d1=id[x][y+];
for(int i=head[now+num];i;i=Next[i]){
if(tmp[i]>=flow[i^]) continue;
if(ver[i]==d0){
++tmp[i],ans[++m]=;
dfs(x+,y);
return;
}
if(ver[i]==d1){
++tmp[i],ans[++m]=;
dfs(x,y+);
return;
}
}
}
int main(){
n=read(),q=read(),p=read();
for(int i=;i<=p;++i)
for(int j=;j<=q;++j)
id[i][j]=++num;
s=,t=num*+;
for(int i=;i<=p;++i)
for(int j=;j<=q;++j)
mp[i][j]=read();
add(s,id[][],n,),add(id[p][q],t,n,);
for(int i=;i<=p;++i)
for(int j=;j<=q;++j){
if(mp[i][j]&) continue;
add(id[i][j],id[i][j]+num,inf,);
if(mp[i][j]) add(id[i][j],id[i][j]+num,,);
}
for(int i=;i<=p;++i)
for(int j=;j<=q;++j){
if(mp[i][j]&) continue;
if(i<p&&mp[i+][j]!=) add(id[i][j]+num,id[i+][j],inf,);
if(j<q&&mp[i][j+]!=) add(id[i][j]+num,id[i][j+],inf,);
}
dinic();
for(int i=;i<=maxflow;++i){
m=,dfs(,);
for(int j=;j<=m;++j) print(i),sr[++C]=' ',print(ans[j]),sr[++C]='\n';
}
Ot();
return ;
}