zoukankan      html  css  js  c++  java
  • 网络流经典模型之一:最大权闭合子图(寿司餐厅)

    前言

    为毛我之前做网络流24题一篇题解都没有写

    正片

    例题

    [六省联考2017]寿司餐厅

    链接

    当时就想着用DP搞,结果死活搞不出那个m=1的做法

    最大权闭合子图介绍

    给你新的一道题目,有(n)个点,每个点有个(a)值,选了就会加上其(a)值,那么很明显加上全部正的(a)即可。

    但是现在要求给你一些关系:选了(x)必须选(y)

    我们现在的(ans)先加上所有的正数。

    那么,考虑最小割,如果在最小割中割了(x)(S)的边,表示不选(x),而割了(x)(T)的边,然后需要注意的是,边权不是价值,而是代价,也就是需要从(ans)中减去的东西。(当然,倒过来应该也没有问题。)

    对于一个点(i),如果(a_i>0),则向(S)连边权为(a_i)的边,向(T)连边权为(0)的边,如果(a_i≤0),则向(S)连边权为(0)的边,向(T)连边权为(-a_i)的边。

    好,那么如果选了(x)必须选(y),就把(x)(y)连一条边,边权为(∞),为什么?

    因为如果(x)选了,割了与(T)的边,(y)不选,割了与(S)的边,那么就一定存在一条路径:(S->x->y->T)

    所以(x)选了,(y)必须被选。

    这就是最大权闭合子图。

    做法

    仔细一看,对于(d_{i,j})而言,选了其必须选择(d_{i+1,j},d_{i,j-1}),而对于(d_{i,i})而言,选了其必须删去(i)的代号,而对于(i),如果其被选择,那么也要删去其代号的平方乘(m)

    然后跑Dinic即可。

    代码

    #include<cstdio>
    #include<cstring>
    #define  N  110
    #define  NN  12000
    #define  M  110000
    using  namespace  std;
    inline  int  mymin(int  x,int  y){return  x<y?x:y;}
    struct  node
    {
    	int  y,next,c;
    }a[M];int  len=1,last[NN];
    inline  void  ins_node(int  x,int  y,int  c){len++;a[len].y=y;a[len].c=c;a[len].next=last[x];last[x]=len;}
    inline  void  ins(int  x,int  y,int  c){ins_node(x,y,c);ins_node(y,x,0);}
    int  list[NN],head,tail,h[NN],st,ed;
    bool  bfs()
    {
    	memset(h,0,sizeof(h));h[ed]=1;
    	head=1;tail=1;list[1]=ed;
    	while(head<=tail)
    	{
    		int  x=list[head++];
    		for(int  k=last[x];k;k=a[k].next)
    		{
    			int  y=a[k].y;
    			if(a[k^1].c  &&  !h[y])
    			{
    				h[y]=h[x]+1;
    				list[++tail]=y;
    			}
    		}
    	}
    	return  h[st];
    }
    int  dinic(int  x,int  f)
    {
    	if(x==ed)return  f;
    	int  s=0,t;
    	for(int  k=last[x];k;k=a[k].next)
    	{
    		int  y=a[k].y;
    		if(a[k].c  &&  h[x]==h[y]+1)
    		{
    			s+=t=dinic(y,mymin(f-s,a[k].c));
    			a[k].c-=t;a[k^1].c+=t;
    			if(s==f)return  s;
    		}
    	}
    	h[x]=0;
    	return  s;
    }
    bool  v[1100];
    int  ans=0;
    inline  void  jian(int  x,int  v)
    {
    	if(v>0)
    	{
    		ans+=v;
    		ins(st,x,v);
    	}
    	else  if(v<0)ins(x,ed,-v);
    }
    int  n,m,d[N][N];
    int  main()
    {
    	scanf("%d%d",&n,&m);
    	st=n*n+n+1000+1;ed=st+1;
    	for(int  i=1;i<=n;i++)
    	{
    		int  x;scanf("%d",&x);
    		if(!v[x]  &&  m)jian(n*n+x,-m*x*x),v[x]=1;
    		jian(n*n+1000+i,-x);
    		ins(n*n+1000+i,n*n+x,999999999);
    	}
    	for(int  i=1;i<=n;i++)
    	{
    		for(int  j=i;j<=n;j++)
    		{
    			scanf("%d",&d[i][j]);
    			jian((i-1)*n+j,d[i][j]);
    		}
    	}
    	for(int  i=1;i<=n;i++)
    	{
    		for(int  j=i;j<=n;j++)
    		{
    			if(i==j)ins((i-1)*n+j,n*n+1000+i,999999999);
    			else  ins((i-1)*n+j,i*n+j,999999999),ins((i-1)*n+j,(i-1)*n+j-1,999999999);
    		}
    	}
    	while(bfs())
    	{
    		ans-=dinic(st,999999999);
    	}
    	printf("%d
    ",ans);
    	return  0;
    }
    /*
    1-n^2表示d(i,j)
    n^2+1-n^2+1000表示第i个代号。
    n^2+1001-n^2+1000+n表示第i个数字,减去其代号 
    */
    
  • 相关阅读:
    数据存储之iOS断点续传
    使用MVC4,Ninject,EF,Moq,构建一个真实的应用电子商务SportsStore(十一)
    使用MVC4,Ninject,EF,Moq,构建一个真实的应用电子商务SportsStore(十)
    使用MVC4,Ninject,EF,Moq,构建一个真实的应用电子商务SportsStore(九)
    获取当前页面url中的参数 coffeescript+node.js+angular
    自定义异步线程池工具,用于执行异步方法
    @ComponentScan 扫包 @Import添加组件
    properties解决中文乱码
    Spring Cloud Config配置中心(五)
    Spring Cloud Zuul路由转发(四)
  • 原文地址:https://www.cnblogs.com/zhangjianjunab/p/13804762.html
Copyright © 2011-2022 走看看