洛谷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 }
深深地明白自己的弱小