战争

战争

题目描述

X国和Y国是死对头,X国有N个炮台, Y国有M个基地和K个发电站,炮台、基地、发电站所在的位置的坐标都是整数。Y国的每个发电站能对距离其L以内(包括L)的基地供电。X国的每个炮台都可以发射无限次,每次发射可以击毁一个基地或者一个发电站,消耗的能量为两者距离的平方,这里的距离是欧几里德距离。X国决定要摧毁Y国的所有基地,我们说Y国的某个基地被摧毁的条件是:基地本身被直接摧毁或者对其供电的所有发电站被击。
问X国摧毁Y国所有基地需要消耗的总能量最小是多少。
提示:点(X1,Y1)和点(X2,Y2)的欧几里德距离是:
dis = sqrt( (X2-X1)* (X2-X1) + (Y2-Y1)* (Y2-Y1)).

输入格式 1894.in

第一行:四个整数:N、M、K、L。1 <= N、M、K <= 50. 1<=L<=2000.
第二行:N个整数,第i个整数表示第i个炮台的横坐标。
第三行:N个整数,第i个整数表示第i个炮台的纵坐标。
第四行:M个整数,第i个整数表示第i个基地的横坐标。
第五行:M个整数,第i个整数表示第i个基地的纵坐标。
第六行:K个整数,第i个整数表示第i个发电站的横坐标。
第七行:K个整数,第i个整数表示第i个发电站的纵坐标。
所有的坐标的范围:[-500,500]。所有的炮台、基地、发电站不会重复。
数据保证每个基地至少有一个发电站为其供电。

输出格式 1894.out

问X国摧毁Y国所有基地需要消耗的总能量最小是多少。



    题目中,有很多限制。需要一一去除,才能明朗起来。

    首先,销毁每个发电站、基地的能量值,需要进行预处理,即所有大炮打它消耗能量中的最小值。

    再者,对题意进行分析:我们可以打发电站,也可以打基地。其中,每个发电站可能对应许多个基地。如果基地的所有发电站都被销毁,则基地也被销毁。  

    这就是个最小割问题。将其转化成图,就变成这个样子:可以割发电站,也可以割基地;且要构造,使得从s能到t为非法的。因此,可以如下构图:

    1)建一个源点S,连接所有发电站,权值为销毁它的能量值。

    2) 从所有发电站出发,连接其能供电的基地,权值为INF

    3)从基地出发,连接汇点T,权值为销毁它的能量值。

    根据最大流最小割定理,直接在原图中跑一遍最大流,即为答案。

    代码如下:

#include
#include
#include
#include
#include
using namespace std;
const int MAXN=55,MAXE=100005,INF=1e7+5,MAXNO=1005;
int head[MAXNO],v[MAXNO],dpl[MAXN],dst[MAXN];
int n,m,k,l,s,t,cur=-1;
long long ans=0;
//1894.cpp
struct wyy
{
	int x,y;
}cannon[MAXN],place[MAXN],station[MAXN];
struct e
{
	int to,next,va;
}edge[MAXE];
void add(int from,int to,int va)
{
	edge[++cur].to=to;
	edge[cur].next=head[from];
	edge[cur].va=va;
	head[from]=cur;
}
void Read()
{
	//ͼ: ·¢µçÕ¾ »ùµØ 
	cin>>n>>m>>k>>l;//nΪÅŲ́£¬mΪ»ùµØ£¬kΪ·¢µçÕ¾£¬lΪ·¢µç¾àÀ루ÐèÆ½·½£©
	
	s=0;
	t=k+m+1;
	
	for(int i=1;i<=n;i++)	
		cin>>cannon[i].x;//ÅÚ 
	for(int i=1;i<=n;i++)
		cin>>cannon[i].y;
	
	for(int i=1;i<=m;i++)
		cin>>place[i].x;
	for(int i=1;i<=m;i++)
		cin>>place[i].y;
		
	for(int i=1;i<=k;i++)
		cin>>station[i].x;
	for(int i=1;i<=k;i++)
		cin>>station[i].y;
		
	memset(head,-1,sizeof(head));
}
void First_prepare()
{
	//±éÀúÿ¸ö»ùµØ£¬¿´ÅŲ́µ½ËüÄÜÁ¿µÄ×îСֵ 
	int xdiff,ydiff,dis;
	for(int i=1;i<=m;i++)//»ùµØ£¬place 
	{
		dis=INF;
		for(int j=1;j<=n;j++)//ÅŲ́£¬cannon 
		{
			xdiff=place[i].x-cannon[j].x;
			ydiff=place[i].y-cannon[j].y;
		    dis=min(dis,xdiff*xdiff+ydiff*ydiff);
		}
		dpl[i]=dis;
		//ans+=dpl[i];
	}
	//±éÀúÿ¸ö·¢ÉäÕ¾£¬¿´ÅŲ́µ½ËüÄÜÁ¿×îСֵ 
	for(int i=1;i<=k;i++)//·¢ÉäÕ¾£¬station 
	{
		dis=INF;
		for(int j=1;j<=n;j++)//ÅŲ́£¬cannon 
		{
			xdiff=station[i].x-cannon[j].x;
			ydiff=station[i].y-cannon[j].y;
			dis=min(dis,xdiff*xdiff+ydiff*ydiff);
		}
		dst[i]=dis;
	}
}
void Make_picture()
{
	int xdiff,ydiff,dis;
	for(int i=1;i<=k;i++)//·¢ÉäÕ¾ s->·¢µçÕ¾ 
	{
		add(s,i,dst[i]);
		add(i,s,0);
	}
	for(int i=1;i<=k;i++)//·¢µçÕ¾Á¬ 
	{
		for(int j=1;j<=m;j++)
		{
			xdiff=station[i].x-place[j].x;
			ydiff=station[i].y-place[j].y;
		    dis=xdiff*xdiff+ydiff*ydiff;
			if(dis<=l*l)	
			{
				add(i,k+j,INF);
				add(k+j,i,0);
			}
		}
	}
	//»ùµØµ½t 
	for(int i=1;i<=m;i++)
	{
		add(k+i,t,dpl[i]);
		add(t,k+i,0);
	}
}	
int dfs(int cur,int mina)
{
	if(cur==t)	return mina;
	v[cur]=1;
	int h=head[cur];
	while(h!=-1)
	{
		int to=edge[h].to,va=edge[h].va;
		if(v[to]==0&&va!=0)
		{
			int res=dfs(to,min(mina,va));
			if(res!=0)
			{
				edge[h].va-=res;
				edge[h^1].va+=res;
				return res;
			}
		}
		h=edge[h].next;
	}
	return 0;
}
void Ed()
{
	while(1)
	{
		memset(v,0,sizeof(v));
		int res=dfs(s,INF);
		if(res==0)	break;
		ans+=res;
	}
}
int main()
{

	ios::sync_with_stdio(false);
	Read();
	First_prepare();
	Make_picture();	
	Ed();
	cout<

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值