• [BZOJ3171/Luogu3965][TJOI2013]循环格


    题目链接:

    BZOJ3171

    Luogu3965

    首先,有一个很显然的结论,每一个格点都要有且只有一条入边,因为整张图有(r*c)个点和边,每个点都要有入边。

    现在要平均分配每一条边,次数最小,那么就很简单了,费用流。

    把每个点拆成入点和出点,对于每个入点,和源点连边,容量(1),费用(0),表示可以向其他点贡献入边。

    对于每个点向四周连边,容量为(1)(可以向四周连边),若方向与箭头相同费用为(0)(不需要改变),否则为(1)(需要修改)。

    对于每个出点向汇点连边,容量(1),费用(0)(得到了一条入边)。

    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define ID(x,y,z) ((z)*n*m+((x)-1)*m+(y))
    
    inline int Min(int a,int b){return a<b?a:b;}
    inline int Max(int a,int b){return a>b?a:b;}
    
    int n,m,St,Ed,MaxFlow,MinCost;
    int Head[505],Next[6005],To[6005],Val[6005],Cos[6005],En=1;
    int Pre[505],Ref[505],Dis[505];
    char Grid[20];
    bool Inq[505];
    const int nx[]={-1,1,0,0},ny[]={0,0,-1,1};
    const char s[]={'U','D','L','R'};
    
    inline void Add(int x,int y,int z,int w)
    {
    	Next[++En]=Head[x],To[Head[x]=En]=y,Val[En]=z,Cos[En]=+w;
    	Next[++En]=Head[y],To[Head[y]=En]=x,Val[En]=0,Cos[En]=-w;
    }
    
    bool SPFA()//压行费用流,不要在意
    {
    	std::queue<int> q;
    	memset(Dis,0x3f,sizeof Dis);
    	q.push(St),Dis[St]=0,Ref[St]=1<<30;
    	for(int x,y;!q.empty();q.pop(),Inq[x]=false)
    		for(int i=Head[x=q.front()];i;i=Next[i])
    			if(Val[i]&&Dis[y=To[i]]>Dis[x]+Cos[i])
    			{
    				Dis[y]=Dis[x]+Cos[Pre[y]=i];
    				Ref[y]=Min(Ref[x],Val[i]);
    				if(!Inq[y])q.push(y),Inq[y]=true;
    			}
    	if(Dis[Ed]==0x3f3f3f3f)return false;
    	MaxFlow+=Ref[Ed],MinCost+=Ref[Ed]*Dis[Ed];
    	for(int x=Ed,i;x!=St;x=To[i^1])
    		Val[i=Pre[x]]-=Ref[Ed],Val[i^1]+=Ref[Ed];
    	return true;
    }
    
    int main()
    {
    	scanf("%d%d",&n,&m),St=n*m<<1|1,Ed=St+1;
    	for(int i=1;i<=n;++i)
    	{
    		scanf("%s",Grid+1);
    		for(int j=1;j<=m;++j)
    		{
    			int t=std::find(s,s+4,Grid[j])-s;
    			Add(St,ID(i,j,0),1,0);
    			Add(ID(i,j,1),Ed,1,0);//向源点与汇点连边
    			for(int k=0;k<4;++k)
    			{
    				int wx=i+nx[k],wy=j+ny[k];//箭头方向
    				if(!wx)wx=n;
    				else if(wx>n)wx=1;
    				if(!wy)wy=m;
    				else if(wy>m)wy=1;//边界处理
    				Add(ID(i,j,0),ID(wx,wy,1),1,k!=t);
    			}
    		}
    	}
    	while(SPFA());
    	printf("%d
    ",MinCost);
    	return 0;
    }
    
  • 相关阅读:
    CDOJ 1059 秋实大哥与小朋友 STL(set)+离散化+BIT区间更新单点查询
    hdu 1754 线段树 水题 单点更新 区间查询
    ZOJ 2301 离散化
    hdu 1166 线段树 区间求和 +单点更新 CD模板
    UVA 12299 线段树 ( 单点跟新 , 区间查询)
    TTTTTTTTTTTTT LA 2191 树状数组 稍修改
    TTTTTTTTTTT LA 4329 BIT模版
    POJ 1912 凸包
    对django模型中的objects的理解
    巨蟒python全栈开发django4:url反向解析图解&&模板渲染2
  • 原文地址:https://www.cnblogs.com/LanrTabe/p/10208693.html
Copyright © 2020-2023  润新知