• 【BZOJ3171】[TJOI2013] 循环格(网络流)


    点此看题面

    大致题意: 给你一个循环格,每个格子有一个方向。问你至少修改多少格子,才能使从每个格子出发都能回到原格子。

    建图

    这是道网络流题目,主要就是考虑如何建图。

    我们可以把每个点拆成两个点,一个入点,一个出点。

    连边有以下两种:

    • 超级源向每个点出点、每个点入点向超级汇连一条容量为(1),代价为(0)的边。
    • 每个点出点向这个点在矩阵中相邻的点的入点连一条容量为(1)的边,若方向与格子原先方向相同,代价为(0),不同时代价为(1)

    然后跑最小费用最大流就可以了。

    代码

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 15
    #define INF 1e9
    using namespace std;
    int n,m;char a[N+5][N+5];
    template<int PS,int ES> class Dinic//最小费用最大流
    {
    	private:
    		#define Else(x) ((((x)-1)^1)+1)
    		#define add(x,y,f,c) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y,e[ee].F=f,e[ee].C=c)
    		int ee,lnk[PS+5],lst[PS+5],Iq[PS+5],F[PS+5],C[PS+5];queue<int> q;
    		struct edge {int to,nxt,F,C;}e[2*ES+5];
    		I bool SPFA()//SPFA找增广路
    		{
    			RI i,k;for(i=1;i<=2*n*m+2;++i) F[i]=C[i]=INF;C[S]=0,q.push(S),Iq[S]=1;
    			W(!q.empty())
    			{
    				for(Iq[k=q.front()]=0,q.pop(),i=lnk[k];i;i=e[i].nxt) e[i].F&&C[k]+e[i].C<C[e[i].to]&&
    				(
    					C[e[i].to]=C[k]+e[lst[e[i].to]=i].C,F[e[i].to]=min(F[k],e[i].F),
    					!Iq[e[i].to]&&(q.push(e[i].to),Iq[e[i].to]=1)
    				);
    			}return F[T]!=INF;
    		}
    	public:
    		int S,T;I Dinic() {S=1,T=2;}
    		I int PI(CI x,CI y) {return (x-1)*m+y+2;}I int PO(CI x,CI y) {return (x+n-1)*m+y+2;}
    		I void Add(CI x,CI y,CI f,CI c) {add(x,y,f,c),add(y,x,0,-c);}//连边
    		I void Solve()
    		{
    			RI x,t=0;W(SPFA())
    			{
    				x=T,t+=F[T]*C[T];//统计最小费用
    				W(x^S) e[lst[x]].F-=F[T],e[Else(lst[x])].F+=F[T],x=e[Else(lst[x])].to;//修改源到汇路径上的残量
    			}printf("%d",t);//输出最小费用
    		}
    };Dinic<2*N*N+2,6*N*N> D;
    int main()
    {
    	RI i,j;for(scanf("%d%d",&n,&m),i=1;i<=n;++i) scanf("%s",a[i]+1);
    	for(i=1;i<=n;++i) for(j=1;j<=m;++j)
    		#define lst(x,t) ((x)^1?(x)-1:(t))
    		#define nxt(x,t) ((x)^(t)?(x)+1:1)
    		D.Add(D.S,D.PO(i,j),1,0),D.Add(D.PI(i,j),D.T,1,0),//与超级源、超级汇连边
    		D.Add(D.PO(i,j),D.PI(lst(i,n),j),1,a[i][j]!='U'),//与相邻点连边
    		D.Add(D.PO(i,j),D.PI(nxt(i,n),j),1,a[i][j]!='D'),//与相邻点连边
    		D.Add(D.PO(i,j),D.PI(i,lst(j,m)),1,a[i][j]!='L'),//与相邻点连边
    		D.Add(D.PO(i,j),D.PI(i,nxt(j,m)),1,a[i][j]!='R');//与相邻点连边
    	return D.Solve(),0;
    }
    
  • 相关阅读:
    vue typescript 父子组件间值的传递
    flex 布局列表自动换行
    css文字两端对齐
    webstorm windows 常用快捷键
    vue elmentUi el-scrollbar 美化滚动条样式
    简述在Vue脚手架中,组件以及父子组件(非父子组件)之间的传值
    简述Vue的实例属性、实例方法
    Js基本类型中常用的方法总结
    简述Vue中的过滤器
    简述Vue中的计算属性
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/BZOJ3171.html
Copyright © 2020-2023  润新知