Member Single Round Match 465 Round 1 - Division I, Level Two GreenWarfareze

有一些敌军据点,有一些能源基地,基地给和它距离小于R的点提供能量。你有一些炮台,摧毁一个据点有两种方法,一种是直接摧毁据点,一种是摧毁给他提供能源的所有基地。用一个炮台摧毁一个目标的代价是欧几里得距离的平方。问你摧毁所有据点的最小代价。

解法:二分图最小点权覆盖。

预处理出摧毁一个基地和一个据点的的最小代价。以据点为X部,源点连流量为摧毁代价的边,基地为Y部,汇点连流量为摧毁代价的边,如果一个基地给一个据点提供能量,在两部之间连接流量为无穷的边。从源点向汇点求最小割(最大流)即可。

#include <bits/stdc++.h>
#define maxn 1009
#define maxm 2000009
#define INF 1e9
using namespace std;
struct Edge
{
    int v,next,cap;
}edge[maxm];
int head[maxn],h[maxn],gap[maxn],tot,n,src,des,N;
inline void addedge(int u,int v,int cap)
{
    edge[tot].v=v;
    edge[tot].cap=cap;
    edge[tot].next=head[u];
    head[u]=tot++;
    edge[tot].v=u;
    edge[tot].cap=0;
    edge[tot].next=head[v];
    head[v]=tot++;
}
int dis(int x1,int y1,int x2,int y2)
{
	return (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2);
}
inline int dfs(int u,int cap)
{
    if(u==des)return cap;
    int minh=n-1;
    int lv=cap,d;
    for(int e=head[u];e!=-1;e=edge[e].next)
    {
        int v=edge[e].v;
        int w=edge[e].cap;
        if(w>0)
        {
            if(h[v]+1==h[u])
            {
                d=min(lv,edge[e].cap);
                d=dfs(v,d);
                edge[e].cap-=d;
                edge[e^1].cap+=d;
                lv-=d;
                if(h[src]>=n)return cap-lv;
                if(lv==0)
                    break;
            }
            minh=min(minh,h[v]);
        }
    }
    if(lv==cap)
    {
        --gap[h[u]];
        if(gap[h[u]]==0)h[src]=n;
        h[u]=minh+1;
        ++gap[h[u]];
    }
    return cap-lv;
}
int sap()
{
    int res=0;
    memset(gap,0,sizeof(gap));
    memset(h,0,sizeof(h));
    gap[0]=n;
    while(h[src]<n)res+=dfs(src,INF);
    return res;
}
class GreenWarfare
{
public:int minimumEnergyCost(vector <int> canonX, vector <int> canonY, vector <int> baseX, vector <int> baseY, vector <int> plantX, vector <int> plantY, int energySupplyRadius)
	{
		int base=baseX.size();
		src=0;
		memset(head,-1,sizeof(head));tot=0;
		for(int i=0;i<base;i++)
		{
			int cur=INF;
			for(int j=0;j<(int)canonX.size();j++)
			{
				cur=min(cur,dis(canonX[j],canonY[j],baseX[i],baseY[i]));
			}
			addedge(src,i+1,cur);
		}
		int plant=plantX.size();
		des=base+plant+1;
		n=des+1;
		for(int i=0;i<plant;i++)
		{
			int cur=INF;
			for(int j=0;j<(int)canonX.size();j++)
			{
				cur=min(cur,dis(plantX[i],plantY[i],canonX[j],canonY[j]));
			}
			addedge(base+i+1,des,cur);
		}
		for(int i=0;i<base;i++)
		{
			for(int j=0;j<plant;j++)
			{
				if(dis(baseX[i],baseY[i],plantX[j],plantY[j])<=energySupplyRadius*energySupplyRadius)
				{
					addedge(i+1,j+base+1,INF);
				}
			}
		}
		return sap();
	}
};


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值