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

传送门

 

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

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

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

  1 //minamoto
  2 #include<iostream>
  3 #include<cstdio>
  4 #include<cstring>
  5 #include<queue>
  6 #define inf 0x3f3f3f3f
  7 using namespace std;
  8 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
  9 char buf[1<<21],*p1=buf,*p2=buf;
 10 inline int read(){
 11     #define num ch-'0'
 12     char ch;bool flag=0;int res;
 13     while(!isdigit(ch=getc()))
 14     (ch=='-')&&(flag=true);
 15     for(res=num;isdigit(ch=getc());res=res*10+num);
 16     (flag)&&(res=-res);
 17     #undef num
 18     return res;
 19 }
 20 char sr[1<<21],z[20];int C=-1,Z;
 21 inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
 22 inline void print(int x){
 23     if(C>1<<20)Ot();
 24     while(z[++Z]=x%10+48,x/=10);
 25     while(sr[++C]=z[Z],--Z);
 26 }
 27 const int N=5005,M=50005;
 28 int ver[M],Next[M],head[N],edge[M],flow[M],tmp[M],tot=1;
 29 int dis[N],disf[N],Pre[N],last[N],vis[N],maxflow=0;
 30 int ans[N],m=0;
 31 int id[55][55],mp[55][55];
 32 int n,p,q,s,t,num=0;
 33 queue<int> Q;
 34 inline void add(int u,int v,int f,int e){
 35     ver[++tot]=v,Next[tot]=head[u],head[u]=tot,flow[tot]=f,edge[tot]=e;
 36     ver[++tot]=u,Next[tot]=head[v],head[v]=tot,flow[tot]=0,edge[tot]=-e;
 37 }
 38 bool spfa(){
 39     memset(dis,0xef,sizeof(dis));
 40     Q.push(s),dis[s]=0,disf[s]=inf,Pre[t]=-1;
 41     while(!Q.empty()){
 42         int u=Q.front();Q.pop();vis[u]=0;
 43         for(int i=head[u];i;i=Next[i]){
 44             int v=ver[i];
 45             if(flow[i]&&dis[v]<dis[u]+edge[i]){
 46                 dis[v]=dis[u]+edge[i],last[v]=i,Pre[v]=u;
 47                 disf[v]=min(disf[u],flow[i]);
 48                 if(!vis[v]) vis[v]=1,Q.push(v);
 49             }
 50         }
 51     }
 52     return ~Pre[t];
 53 }
 54 void dinic(){
 55     while(spfa()){
 56         int u=t;maxflow+=disf[t];
 57         while(u!=s){
 58             flow[last[u]]-=disf[t];
 59             flow[last[u]^1]+=disf[t];
 60             u=Pre[u];
 61         }
 62     }
 63 }
 64 void dfs(int x,int y){
 65     int now=id[x][y],d0=id[x+1][y],d1=id[x][y+1];
 66     for(int i=head[now+num];i;i=Next[i]){
 67         if(tmp[i]>=flow[i^1]) continue;
 68         if(ver[i]==d0){
 69             ++tmp[i],ans[++m]=0;
 70             dfs(x+1,y);
 71             return;
 72         }
 73         if(ver[i]==d1){
 74             ++tmp[i],ans[++m]=1;
 75             dfs(x,y+1);
 76             return;
 77         }
 78     }
 79 }
 80 int main(){
 81     n=read(),q=read(),p=read();
 82     for(int i=1;i<=p;++i)
 83     for(int j=1;j<=q;++j)
 84     id[i][j]=++num;
 85     s=0,t=num*2+1;
 86     for(int i=1;i<=p;++i)
 87     for(int j=1;j<=q;++j)
 88     mp[i][j]=read();
 89     add(s,id[1][1],n,0),add(id[p][q],t,n,0);
 90     for(int i=1;i<=p;++i)
 91     for(int j=1;j<=q;++j){
 92         if(mp[i][j]&1) continue;
 93         add(id[i][j],id[i][j]+num,inf,0);
 94         if(mp[i][j]) add(id[i][j],id[i][j]+num,1,1);
 95     }
 96     for(int i=1;i<=p;++i)
 97     for(int j=1;j<=q;++j){
 98         if(mp[i][j]&1) continue;
 99         if(i<p&&mp[i+1][j]!=1) add(id[i][j]+num,id[i+1][j],inf,0);
100         if(j<q&&mp[i][j+1]!=1) add(id[i][j]+num,id[i][j+1],inf,0);
101     }
102     dinic();
103     for(int i=1;i<=maxflow;++i){
104         m=0,dfs(1,1);
105         for(int j=1;j<=m;++j) print(i),sr[++C]=' ',print(ans[j]),sr[++C]='\n';
106     }
107     Ot();
108     return 0;
109 }

 

posted @ 2018-08-20 20:12  bztMinamoto  阅读(234)  评论(0编辑  收藏  举报
Live2D