P3356 火星探险问题
生活随笔
收集整理的這篇文章主要介紹了
P3356 火星探险问题
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
網(wǎng)絡(luò)流24題之一。
因為石頭只能取一次,因此容易想到用拆點限制。于是經(jīng)典的建圖,然后跑費用流。
這里說一下輸出路徑:用dfs隨著 有流過的邊 輸出即可,因為我的建圖點與點之間初始滿流是INF,所以比INF小的就是流過的邊(即有被流量),并且INF-現(xiàn)在的流量就是經(jīng)過次數(shù)。
那么每次找完方案并把流量++即可避免重復(fù)。
細(xì)節(jié)參考代碼:
#include<iostream> #include<cstdio> #include<queue> #include<cstring> using namespace std; const int N=5000+10; const int M=50000+10; const int INF=0x3f3f3f3f; int n,m,s,t,bs,k,maxflow,mincost,mp[50][50]; struct edge{int nxt,to,cap,cost; }edges[M<<1]; int cnt=1,head[N],pre[N];void add_edge(int x,int y,int z,int c) {edges[++cnt].nxt=head[x]; edges[cnt].to=y; edges[cnt].cap=z; edges[cnt].cost=c; head[x]=cnt; }queue<int> q; int dis[N],lim[N]; bool inq[N]; bool spfa(int s,int t) {while (!q.empty()) q.pop();memset(dis,0x3f,sizeof(dis));memset(inq,0,sizeof(inq));dis[s]=0; inq[s]=1; lim[s]=INF; q.push(s);while (!q.empty()) {int x=q.front(); q.pop();for (int i=head[x];i;i=edges[i].nxt) {edge e=edges[i];if (e.cap && dis[x]+e.cost<dis[e.to]) {dis[e.to]=dis[x]+e.cost;pre[e.to]=i; //即e.to這個點是從i這條邊來的 lim[e.to]=min(lim[x],e.cap);if (!inq[e.to]) { q.push(e.to); inq[e.to]=1; }}}inq[x]=0;}return !(dis[t]==INF); }void MCMF() {maxflow=0; mincost=0;while (spfa(s,t)) {int now=t;maxflow+=lim[t];mincost+=lim[t]*dis[t];while (now!=s) {edges[pre[now]].cap-=lim[t];edges[pre[now]^1].cap+=lim[t];now=edges[pre[now]^1].to;}} }int id(int x,int y) { return (x-1)*m+y; }void dfs(int k,int x,int y) { //用dfs順序輸出方案 if (x==n && y==m) return;int u=id(x,y)+bs;for (int i=head[u];i;i=edges[i].nxt) {int v=edges[i].to;if (edges[i].cap<INF) { //初始流量為INF,小于INF即這條邊流過 if ((v-1)/m+1>x) printf("%d %d\n",k,0); else printf("%d %d\n",k,1);edges[i].cap++; //重點:是他的流量++,避免下次路徑重復(fù) dfs(k,(v-1)/m+1,(v-1)%m+1);return;}} }//P3356 火星探險問題 費用流+輸出路徑 int main() {cin>>k>>m>>n;for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) scanf("%d",&mp[i][j]);s=0; t=2*n*m+1; bs=n*m;for (int i=1;i<=n;i++)for (int j=1;j<=m;j++) {if (mp[i][j]==0) add_edge(id(i,j),id(i,j)+bs,INF,0),add_edge(id(i,j)+bs,id(i,j),0,0);if (mp[i][j]==1) add_edge(id(i,j),id(i,j)+bs,0,0),add_edge(id(i,j)+bs,id(i,j),0,0);if (mp[i][j]==2) {add_edge(id(i,j),id(i,j)+bs,1,-1); add_edge(id(i,j)+bs,id(i,j),0,1);add_edge(id(i,j),id(i,j)+bs,INF,0),add_edge(id(i,j)+bs,id(i,j),0,0);}if (i<n) add_edge(id(i,j)+bs,id(i+1,j),INF,0),add_edge(id(i+1,j),id(i,j)+bs,0,0);if (j<m) add_edge(id(i,j)+bs,id(i,j+1),INF,0),add_edge(id(i,j+1),id(i,j)+bs,0,0);}add_edge(s,id(1,1),k,0); add_edge(id(1,1),s,0,0);add_edge(id(n,m),t,k,0); add_edge(t,id(n,m),0,0);MCMF();for (int i=1;i<=maxflow;i++) dfs(i,1,1); //輸出總共有maxflow個方案 return 0; }?
轉(zhuǎn)載于:https://www.cnblogs.com/clno1/p/10725932.html
總結(jié)
以上是生活随笔為你收集整理的P3356 火星探险问题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: web大作业介绍自己的家乡_【天成好作文
- 下一篇: 游戏开发常遇到数据一致性BUG,怎么解?