[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
原创粉丝点击