现在的位置: 首页 > 综合 > 正文

USACO Section 3.4 Electric Fence(数论)

2013年12月05日 ⁄ 综合 ⁄ 共 5271字 ⁄ 字号 评论关闭

Electric Fence
Don Piele

In this problem, `lattice points' in the plane are points with integer coordinates.

In order to contain his cows, Farmer John constructs a triangular electric fence by stringing a "hot" wire from the origin (0,0) to a lattice point [n,m] (0<=;n<32000, 0<m<32000), then to a lattice point on the
positive x axis [p,0] (p>0), and then back to the origin (0,0).

A cow can be placed at each lattice point within the fence without touching the fence (very thin cows). Cows can not be placed on lattice points that the fence touches. How many cows can a given fence hold?

PROGRAM NAME: fence9

INPUT FORMAT

The single input line contains three space-separated integers that denote n, m, and p.

SAMPLE INPUT (file fence9.in)

7 5 10

OUTPUT FORMAT

A single line with a single integer that represents the number of cows the specified fence can hold.

SAMPLE OUTPUT (file fence9.out)

20

思路:皮克公式 

皮克定理说明了其面积S和内部格点数目a、边上格点数目b的关系:S = a + b/2 - 1。

根据三角形面积公式求出S。如果知道了b,那么三角形内部格点数目a也就求出来了。

可以证明,一条直线((0,0),(n,m))上的格点数等于n与m的最大公约数+1。

即b=gcd(n,m)+1. gcd(n,m)为n与m的最大公约数。

/*
ID:nealgav1
LANG:C++
PROG:fence9
*/
#include<fstream>
#include<cstring>
using namespace std;
ifstream cin("fence9.in");
ofstream cout("fence9.out");
int n,m,p;
int gcd(int a,int b)
{ int z;
  while(b)
  {
    z=b;b=a%b;a=z;
  }
  return z;
}
int kabs(int x)
{
  if(x<0)x=-x;
  return x;
}
int main()
{
  while(cin>>n>>m>>p)
  { if(m==0){cout<<0<<"\n";continue;}
    int sum=m*p;sum>>=1;
    int edge=gcd(n,m)+gcd(kabs(n-p),m)+p;
    sum=sum-edge/2+1;
    cout<<sum<<"\n";
  }
}

USER: Neal Gavin Gavin [nealgav1]
TASK: fence9
LANG: C++

Compiling...
Compile: OK

Executing...
   Test 1: TEST OK [0.000 secs, 3356 KB]
   Test 2: TEST OK [0.000 secs, 3356 KB]
   Test 3: TEST OK [0.000 secs, 3356 KB]
   Test 4: TEST OK [0.000 secs, 3356 KB]
   Test 5: TEST OK [0.000 secs, 3356 KB]
   Test 6: TEST OK [0.000 secs, 3356 KB]
   Test 7: TEST OK [0.000 secs, 3356 KB]
   Test 8: TEST OK [0.000 secs, 3356 KB]
   Test 9: TEST OK [0.000 secs, 3356 KB]
   Test 10: TEST OK [0.000 secs, 3356 KB]
   Test 11: TEST OK [0.000 secs, 3356 KB]
   Test 12: TEST OK [0.000 secs, 3356 KB]

All tests OK.

Your program ('fence9') produced all correct answers! This is your submission #2 for this problem. Congratulations!

Here are the test data inputs:

------- test 1 ----
1 1 2
------- test 2 ----
2 2 4
------- test 3 ----
10 20 10
------- test 4 ----
0 100 100
------- test 5 ----
0 200 20000
------- test 6 ----
100 200 50
------- test 7 ----
10000 100 10
------- test 8 ----
0 20000 2
------- test 9 ----
200 30000 30000
------- test 10 ----
30000 30000 30001
------- test 11 ----
15000 100 30000
------- test 12 ----
0 31999 31999

Keep up the good work!

Thanks for your submission!

Home on the Range
Russ Cox

To count the squares, we first precompute the biggest square with lower right corner at any particular location. This is done by dynamic programming: the biggest square with lower right corner at (i, j) is the minimum
of three numbers:

  • the number of consecutive uneaten grid units to the left
  • the number of consecutive uneaten grid units to the right
  • one plus the size of the biggest square with lower right corner at (i-1, j-1)

Once we've computed this information, counting squares is simple: go to each lower right corner and increment the counters for every square size between 2 and the biggest square ending at that corner.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#define MAXN 250

int goodsq[MAXN][MAXN];
int bigsq[MAXN][MAXN];
int tot[MAXN+1];

int
min(int a, int b)
{
    return a < b ? a : b;
}

void
main(void)
{
    FILE *fin, *fout;
    int i, j, k, l, n, sz;

    fin = fopen("range.in", "r");
    fout = fopen("range.out", "w");
    assert(fin != NULL && fout != NULL);

    fscanf(fin, "%d\n", &n);

    for(i=0; i<n; i++) {
	for(j=0; j<n; j++)
	    goodsq[i][j] = (getc(fin) == '1');
	assert(getc(fin) == '\n');
    }

    /* calculate size of biggest square with lower right corner (i,j) */
    for(i=0; i<n; i++) {
	for(j=0; j<n; j++) {
	    for(k=i; k>=0; k--)
		if(goodsq[k][j] == 0)
		    break;

	    for(l=j; l>=0; l--)
		if(goodsq[i][l] == 0)
		    break;

	    sz = min(i-k, j-l);
	    if(i > 0 && j > 0)
		sz = min(sz, bigsq[i-1][j-1]+1);

	    bigsq[i][j] = sz;
	}
    }

    /* now just count squares */
    for(i=0; i<n; i++)
    for(j=0; j<n; j++)
    for(k=2; k<=bigsq[i][j]; k++)
	tot[k]++;

    for(i=2; i<=n; i++)
	if(tot[i])
	    fprintf(fout, "%d %d\n", i, tot[i]);
				
    exit(0);
}

Greg Price writes:

The posted solution runs in cubic time, with quadratic storage. With a little more cleverness in the dynamic programming, the task can be accomplished with only quadratic time and linear storage, and the same amount
of code and coding effort. Instead of running back along the rows and columns from each square, we use the biggest-square values immediately to the west and north, so that each non-ravaged square's biggest-square value is one more than the minimum of the values
to the west, north, and northwest. This saves time, bringing us from cubic to quadratic time.

Another improvement, which saves space and perhaps cleans up the code marginally, is to keep track of the number of squares of a given size as we go along. This obviates the need to keep a quadratic-size matrix
of biggest-square values, because we only need the most recent row for continuing the computation. As for "ravaged" values, we only use each one once, all in order; we can just read those as we need them.

#include <fstream.h>

ifstream fin("range.in");
ofstream fout("range.out");

const unsigned short maxn = 250 + 5;

unsigned short n;
char fieldpr;
unsigned short sq[maxn]; // biggest-square values
unsigned short sqpr;
unsigned short numsq[maxn]; // number of squares of each size

unsigned short
min3(unsigned short a, unsigned short b, unsigned short c)
{
	if ((a <= b) && (a <= c))
		return a;
	else 
		return (b <= c) ? b : c;
}

void
main()
{
	unsigned short r, c;
	unsigned short i;
	unsigned short tmp;

	fin >> n;

	for (c = 1; c <= n; c++)
		sq[c] = 0;

	for (i = 2; i <= n; i++)
		numsq[i] = 0;

	for (r = 1; r <= n; r++)
	{
		sqpr = 0;
		sq[0] = 0;
		for (c = 1; c <= n; c++)
		{
			fin >> fieldpr;
			if (!(fieldpr - '0'))
			{
				sqpr = sq[c];
				sq[c] = 0;
				continue;
			}

			// Only three values needed.
			tmp = 1 + min3(sq[c-1], sqpr, sq[c]);
			sqpr = sq[c];
			sq[c] = tmp;

			// Only count maximal squares, for now.
			if (sq[c] >= 2)
				numsq[ sq[c] ]++;
		}
	}

	// Count all squares, not just maximal. 
	for (i = n-1; i >= 2; i--)
		numsq[i] += numsq[i+1];

	for (i = 2; i <= n && numsq[i]; i++)
		fout << i << ' ' << numsq[i] << endl;
}


抱歉!评论已关闭.