[BZOJ3171][TJOI2013][最小费用最大流]循环格
来源:互联网 发布:linux top 进程名 编辑:程序博客网 时间:2024/05/17 16:14
<题目>
<算法>
最小费用最大流
<分析>
一眼看出是最小费用最大流,但是就是想不出来建图啊。。。其实关键是要抓住环的性质。所有图上的点的入度和出度都是1。这样就可以把每个点拆成入点和出点,S到出点,入点到T各连一条流量为1的边,表示对入度和出度的限制。然后每个点的出点向四个方向的入点连边,如果不符合原来的方向就设费用为1。跑最小费用最大流即可
<注意>
不要总想着直接把题目跟网络流靠上去……要先分析出一些题目里包含的关键信息,比如本题中的入度出度问题,这是建模的关键
<鸣谢>
感谢ZKY神犇的讲解~
<代码>
/************************************************************** Problem: 3171 User: gaotianyu1350 Language: C++ Result: Accepted Time:28 ms Memory:1428 kb****************************************************************/ #include <cstdio>#include <cstring>#include <cmath>#include <cstdlib>#include <iostream>#include <queue>#include <map>using namespace std; #define INF 1000000000#define MAXNODE 600#define MAXEDGE 6000 int point[MAXEDGE],next[MAXEDGE],v[MAXEDGE],flow[MAXEDGE],cap[MAXEDGE],w[MAXEDGE];bool inq[MAXNODE];int lastedge[MAXNODE],addflow[MAXNODE],dis[MAXNODE],totedge; const int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};map<char,int> duiying; int n,m;char normal[20][20]; void Init(){ memset(point,-1,sizeof(point)); memset(next,-1,sizeof(next)); totedge=-1;} void AddEdge(int x,int y,int theCap,int theDis){ totedge++; next[totedge]=point[x];point[x]=totedge; v[totedge]=y;flow[totedge]=0;cap[totedge]=theCap;w[totedge]=theDis; totedge++; next[totedge]=point[y];point[y]=totedge; v[totedge]=x;flow[totedge]=0;cap[totedge]=0;w[totedge]=-theDis;} bool Spfa(int s,int t,int &MaxFlow,int &MinCost){ queue<int> q; while (!q.empty()) q.pop(); memset(dis,0x7f,sizeof(dis)); memset(inq,0,sizeof(inq)); memset(lastedge,0,sizeof(lastedge)); dis[s]=0;inq[s]=true;addflow[s]=INF; q.push(s); while (!q.empty()) { int now=q.front();q.pop();inq[now]=false; for (int temp=point[now];temp!=-1;temp=next[temp]) if (flow[temp]<cap[temp]&&dis[now]+w[temp]<dis[v[temp]]) { dis[v[temp]]=dis[now]+w[temp]; addflow[v[temp]]=min(addflow[now],cap[temp]-flow[temp]); lastedge[v[temp]]=temp; if (!inq[v[temp]]) { inq[v[temp]]=true; q.push(v[temp]); } } } if (dis[t]>INF) return false; MaxFlow+=addflow[t];MinCost+=addflow[t]*dis[t]; int now=t; while (now!=s) { flow[lastedge[now]]+=addflow[t]; flow[lastedge[now]^1]-=addflow[t]; now=v[lastedge[now]^1]; } return true;} int CalcMinCost(int s,int t){ int MaxFlow=0,MinCost=0; while (Spfa(s,t,MaxFlow,MinCost)); return MinCost;} int main(){ //freopen("input.txt","r",stdin); duiying.clear(); duiying['U']=0; duiying['D']=1; duiying['L']=2; duiying['R']=3; Init(); scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) scanf(" %c",&normal[i][j]); int start=n*m*2+1,end=n*m*2+2; for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) { AddEdge(start,(i-1)*m+j,1,0); AddEdge((i-1)*m+j+n*m,end,1,0); for (int k=0;k<4;k++) { int nextx=i+dir[k][0]; int nexty=j+dir[k][1]; if (nextx==0) nextx=n; if (nextx==n+1) nextx=1; if (nexty==0) nexty=m; if (nexty==m+1) nexty=1; if (duiying[normal[i][j]]==k) AddEdge((i-1)*m+j,(nextx-1)*m+nexty+n*m,1,0); else AddEdge((i-1)*m+j,(nextx-1)*m+nexty+n*m,1,1); } } int Ans=CalcMinCost(start,end); printf("%d\n",Ans);}
0 0
- [BZOJ3171][TJOI2013][最小费用最大流]循环格
- 【bzoj3171】[Tjoi2013]循环格 (费用流)
- 【bzoj3171】【TJOI2013】【循环格】【费用流】
- bzoj3171 [Tjoi2013]循环格(费用流)
- bzoj3171 循环格 最小费用流
- bzoj3171【tjoi2013】循环格
- 【bzoj3171】[Tjoi2013]循环格
- BZOJ3171 Tjoi2013 循环格
- 【bzoj3171】[Tjoi2013]循环格
- BZOJ3171: [Tjoi2013]循环格
- BZOJ3171: [Tjoi2013]循环格
- BZOJ3171: [Tjoi2013]循环格
- bzoj3171 [Tjoi2013]循环格
- bzoj3171循环格(费用流)
- [费用流]BZOJ:3171: [Tjoi2013]循环格
- BZOJ-3171-循环格-TJOI2013-费用流
- 3171: [Tjoi2013]循环格 费用流
- bzoj 3171: [Tjoi2013]循环格 费用流
- 关于hashCode方法的作用
- 配置 yum 源的两种方法
- 黑马程序员学习笔记——泛型的反射
- 关于指针数组和数组指针的浅谈
- Struts
- [BZOJ3171][TJOI2013][最小费用最大流]循环格
- vc如何画圆,并填充颜色
- IP网络层与网络设备之间分组收发原理
- 重新编译 vcl70.bpl
- Centos配置国内yum源
- Overload和Override的区别
- sysfs 之 kobject
- 查询数据库中最大的表
- OPENFIRE支持EMOJI表情