您的位置:首页 > 其它

[BZOJ3171][TJOI2013][最小费用最大流]循环格

2014-04-22 13:59 399 查看
<题目>



<算法>

最小费用最大流

<分析>

一眼看出是最小费用最大流,但是就是想不出来建图啊。。。其实关键是要抓住环的性质。所有图上的点的入度和出度都是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);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息