• zoj 2874 Paratroopers 网络流 最小割


             题目大意:在一个网格上会出现一些火星人,需要消灭他们,因此要在某些行(或列)安装激光枪,并且该激光枪只能杀死该行(或列)的火星人,在某列(或行)安装一个激光枪会产生花费,总的费用为这些费用的乘积,求把所有火星人都杀死的最小总花费。   

             相当于选一些行或列覆盖所有图中的火星人顶点,若把火星人视为边,行和列视为顶点,则可以这样构图:引入源汇s,t,对每个行节点,连接s与行节点,容量为在该行建立激光器的费用,连接列节点与汇点t,容量为在该列建立激光器的费用,若在原网格中点(i,j)上有一个火星人,则连接i,j,容量为无穷大INF,则最小割容量即为最小费用。

             下面简述一下原因,将原图建立成二分图后,对于图中任何一条边,要么在选行节点,要么选列节点,所以可行方案是一个该二分图的点覆盖集,且选某个点就产生花费,因此即求最小点权覆盖集。

             最小点权覆盖一定是极小点覆盖集,但不一定是最小点覆盖集,联想二分图匹配的网络流算法,匹配限制在点,而点覆盖限制在边,最大流和最小割是对偶问题,对偶往往将问题的性质由边转换为点,由点转换为边,所以可以尝试最小割,因此使用上述建图方法,因为对于任意图中一条路径都是s--->u---->v---->t的形式,割的性质是s与t不连通,又因为边(u,v)为无穷大,所以(u,v)不在割中,则条件简化为(s,u)(v,t)中至少有一条边在割中,正好与点覆盖的限制条件相同:每条边(u,v)至少选中一个顶点,最小点权覆盖的目标是最小化点权之和,正好与最小割的目标相同。

              另外,因为总花费为所有花费的乘积,因此现将花费变成他的对数,再求和后exp即可。

    #include <stdio.h>
    #include <string.h>
    #include <math.h>
    #define MAX 110
    #define INF 10000000
    struct node
    {
    	double c,f;
    }map[MAX][MAX];
    int pre[MAX],queue[MAX];
    int s,t;
    int bfs()
    {
    	int i,cur,qs,qe;
    	memset(pre,-1,sizeof(pre));
    	pre[s]=s;
    	qs=0;qe=1;
    	queue[qs]=s;
    	while(qs<qe)
    	{
    		cur=queue[qs++];
    		for(i=0;i<=t;i++)
    		{
    			if(pre[i]==-1&&map[cur][i].c-map[cur][i].f>0)
    			{
    				queue[qe++]=i;
    				pre[i]=cur;
    				if(i==t)
    					return 1;
    			}
    		}
    	}
    	return 0;
    }
    
    double maxflow()
    {
    	double max=0,min;
    	int i;
    	while(bfs())
    	{
    		min=INF;
    		for(i=t;i!=s;i=pre[i])
    			if(map[pre[i]][i].c-map[pre[i]][i].f<min)
    				min=map[pre[i]][i].c-map[pre[i]][i].f;
    		for(i=t;i!=s;i=pre[i])
    		{
    			map[pre[i]][i].f+=min;
    			map[i][pre[i]].f-=min;
    		}
    		max+=min;
    	}
    	return max;
    }
    
    int main()
    {
    	int i,j,n,m,l,r,cc,w;
    	double c;
    	scanf("%d",&w);
    	while(w--)
    	{
    		memset(map,0,sizeof(map));
    		scanf("%d%d%d",&n,&m,&l);
    		s=0;t=n+m+1;
    		for(i=1;i<=n;i++)
    		{
    			scanf("%lf",&c);
    			map[s][i].c=log(c);
    		}
    		for(i=1;i<=m;i++)
    		{
    			scanf("%lf",&c);
    			map[i+n][t].c=log(c);
    		}
    		for(i=1;i<=l;i++)
    		{
    			scanf("%d%d",&r,&cc);
    			map[r][n+cc].c=INF;
    		}
    		printf( "%.4lf
    ",exp( maxflow() ) );
    	}
    	return 0;
    }
    
    	


     

     

     

  • 相关阅读:
    LOJ
    LOJ
    LOJ
    一种树形背包的时间复杂度证明
    [机器学习]第四、五周记录
    [机器学习]第三周记录
    [家里训练20_02_16]C
    [机器学习]第二周记录
    wireshark无响应的问题
    [机器学习]第一周记录
  • 原文地址:https://www.cnblogs.com/vermouth/p/3710204.html
Copyright © 2020-2023  润新知