战争
题目描述
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国所有基地需要消耗的总能量最小是多少。
输入样例 1894.in
题目大意:
要用N个炮台把M个基地,或者可以给此基地供电的供电厂销毁。两个地方的距离为sqrt( (X2-X1)*(X2-X1) + (Y2-Y1)* (Y2-Y1)),需要的能量为:(X2-X1)* (X2-X1) +(Y2-Y1)* (Y2-Y1),也就是两个地方横纵坐标差的平方和。
发电站供电的范围的距离在L以内。
要得出把所有基地捣毁的最小能量。
70%的水分(112/161):
虽然我觉得这种水分实在是太没道理,也可能是数据实在太弱,就是直接把摧毁所有基地需要的最小能量算出来(使用最近的炮台轰炸),再把摧毁所有发射站需要的最小能量算出来。
我索性都没有判断哪些发射站可以给哪些基地供电,再把供不到电的基地格外再轰一次。不知道加多一些判断分数是否会更可观。
正解(161/161):
很明显就是最小割的啦,每一个基地和发电站都是选择最近的炮台轰炸会最好,这样一来,N个炮台就没用了,只要事先预处理出每一个基地和每一个发电站是被多远的炮台所轰。
构图:
1、由源点s链接发电站,边权为最近炮台与发电站的距离。
2、由汇点t链接基地,边权为最近炮台与基地的距离。
3、发电站与可被发电的基地相连,边权为oo。
如图:
#include
#include
#include
#include
using namespace std;
const int maxn=505,oo=100000000;
int n,m,k,l;
int px[maxn],py[maxn],jx[maxn],jy[maxn],fx[maxn],fy[maxn];//p炮台,j基地,f发射站
int cur=-1,head[maxn],s,t,v[2*maxn];
long long ans;
struct mi
{
int next,to,va;
} edge[maxn*maxn];
void add(int from,int to,int va)
{
cur++;
edge[cur].to=to;
edge[cur].va=va;
edge[cur].next=head[from];
head[from]=cur;
}
int Dis(int ax,int bx,int ay,int by)
{
ax-=bx;
ay-=by;
return ax*ax+ay*ay;
}
void init()
{
cin>>n>>m>>k>>l;
for(int i=1;i<=n;i++) cin>>px[i];
for(int j=1;j<=n;j++) cin>>py[j];
for(int i=1;i<=m;i++) cin>>jx[i];
for(int j=1;j<=m;j++) cin>>jy[j];
for(int i=1;i<=k;i++) cin>>fx[i];
for(int j=1;j<=k;j++) cin>>fy[j];
memset(head,-1,sizeof(head));
t=m+k+1;
}
void prepare()
{
for (int i=1; i<=k; i++)
{
int d=oo;
for (int j=1; j<=n; j++) d=min(d, Dis(fx[i],px[j],fy[i],py[j]) );
add(0,i,d);
add(i,0,0);
}
//连发射站
for (int i=1; i<=m; i++)
{
int d=oo;
for (int j=1; j<=n; j++) d=min(d, Dis(jx[i],px[j],jy[i],py[j]) );
add(k+i,t,d);
add(t,k+i,0);
}
//连基地
for (int i=1; i<=k; i++)
{
for (int j=1; j<=m; j++)
{
if ( Dis(fx[i],jx[j],fy[i],jy[j])<=l* l)
{
add(i,k+j,oo);
add(k+j,i,0);
}
}
}
//基地与发射站相连
}
int dfs(int now,int mi)
{
if(now==t) return mi;
v[now]=1;
int h=head[now];
while(h!=-1)
{
int to=edge[h].to,va=edge[h].va;
if(v[to]==0&&va!=0)
{
int kk;
kk=dfs(to,min(va,mi));
if(kk!=0)
{
edge[h].va-=kk;
edge[h^1].va+=kk;
return kk;
}
}
h=edge[h].next;
}
return 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 start()
{
while(1)
{
memset(v,0,sizeof(v));
int res=0;
res=dfs(0,oo);
if(res==0) break;
ans+=res;
}
}
int main()
{
freopen("1894.in","r",stdin);
freopen("1894.out","w",stdout);
init();
prepare();
start();
cout<