http://lightoj.com/volume_showproblem.php?problem=1366
参考文章 http://blog.youkuaiyun.com/diannaok/article/details/7836559
思路:
分两种情况计算。
第一种情况,两个圆水平相切、或者竖直相切。
这种情况很好计算,假设一个(以最大圆直径为宽、以两圆直径之和为长)矩形,在n*m的范围内有多少放法,计算出来即可。
第二种情况,两个圆沿斜线相切(斜线长度为任意 勾股数组 的斜边长度)。
这时候只要枚举斜线两端圆的半径(从1 到 len-1),分别求出所能容纳它的相应的矩形,然后求这个矩形在n*m的范围内有多少放法即可。
#include <stdio.h>
#include <math.h>
#define MAX(X,Y) ((X) > (Y) ? (X) : (Y))
int H,W;
int x[500],y[500],z[500],id=0;
void Ini () //计算勾股数组,约460组
{
int i,j,k;
for (i=1;i<500;i++)
for (j=i+1;j<500;j++)
{
k=(int)(sqrt(i*i+j*j)+0.5); //四舍五入
if (j*j+i*i == k*k)
{
x[id]=i;
y[id]=j;
z[id++]=k;
}
}
}
__int64 Deal ()
{
int i,j,uplimit,h,w;
__int64 sum=0,temp;
uplimit=MAX(H,W);
for (i=2;i<uplimit;i+=2) // 第一种情况
for (j=i;i+j<=uplimit;j+=2)
{
h=i+j;
w=MAX(i,j);
temp=0;
if (H>=h && W>=w)
temp+=(H-h+1)*(W-w+1);
if (W>=h && H>=w)
temp+=(W-h+1)*(H-w+1);
if (i!=j)
temp*=2;
sum+=temp;
}
for (i=0;i<id;i++) // 第二种情况,交点不一定在网格上
for (j=1;j<z[i];j++)
{
temp=0;
//z[i]+x[i]为两圆交错摆放时所占的宽度,MAX(j,z[i]-j)为较大圆的半径
h=MAX(z[i]+x[i],2*MAX(j,z[i]-j));
w=MAX(z[i]+y[i],2*MAX(j,z[i]-j));
if (H>=h && W>=w)
temp+=(H-h+1)*(W-w+1);
if (W>=h && H>=w)
temp+=(W-h+1)*(H-w+1);
//由勾股数组的基本特点"两直角边为一奇一偶,斜边为奇",两圆半径不可能相等
sum+=temp*2;
}
return sum;
}
int main ()
{
int T;
Ini ();
scanf("%d",&T);
for (int cas=1;cas<=T;cas++)
{
scanf("%d%d",&H,&W);
printf("Case %d: %lld\n",cas,Deal());
}
return 0;
}
/*
Input:
5
20 20
8 9
18 15
18 16
18 17
Output:
Case 1: 10338
Case 2: 202
Case 3: 4460
Case 4: 5142
Case 5: 5824
*/