[BZOJ3171][TJOI2013][最小费用最大流]循环格
2014-04-22 13:59
399 查看
<题目>
![](http://www.lydsy.com/JudgeOnline/upload/201305/1.JPG)
<算法>
最小费用最大流
<分析>
一眼看出是最小费用最大流,但是就是想不出来建图啊。。。其实关键是要抓住环的性质。所有图上的点的入度和出度都是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);
}
<算法>
最小费用最大流
<分析>
一眼看出是最小费用最大流,但是就是想不出来建图啊。。。其实关键是要抓住环的性质。所有图上的点的入度和出度都是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);
}
相关文章推荐
- BZOJ_3171_[Tjoi2013]循环格_最小费用最大流
- bzoj 3171: [Tjoi2013]循环格 最小费用最大流
- bzoj3171 [Tjoi2013]循环格
- bzoj 3171: [Tjoi2013]循环格
- 3171: [Tjoi2013]循环格 (最小费用最大流)
- 【BZOJ】【3171】【TJOI2013】循环格
- 【TJOI2013 Day1合集】BZOJ3170 松鼠聚会 BZOJ3171 循环格 BZOJ3172 单词
- BZOJ3171 Tjoi2013 循环格
- BZOJ3171: [Tjoi2013]循环格
- BZOJ 3171 TJOI 2013 循环格 费用流
- BZOJ3171 Tjoi2013 循环格
- bzoj 3171: [Tjoi2013]循环格 费用流
- 【bzoj3171】[Tjoi2013]循环格 (费用流)
- 【bzoj3171】[Tjoi2013]循环格
- BZOJ-3171-循环格-TJOI2013-费用流
- bzoj:3171: [Tjoi2013]循环格
- 【bzoj3171】【TJOI2013】【循环格】【费用流】
- BZOJ 3171 [Tjoi2013]循环格
- BZOJ 3171 [Tjoi2013]循环格(费用流)
- BZOJ 3171: [Tjoi2013]循环格( 费用流 )