【USACO】beads

题目:

You have a necklace of N red, white, or blue beads (3<=N<=350) some of
which are red, others blue, and others white, arranged at random. Here are two
examples for n=29:

                1 2                               1 2
r b b r b r r b
r b b b
r r b r
r r w r
b r w w
b b r r
b b b b
b b r b
r r b r
b r r r
b r r r
r r r b
r b r r r w
Figure A Figure B
r red bead
b blue bead
w white bead

The beads considered first and second in the text that follows have been
marked in the picture.

The configuration in Figure A may be represented as a string of b‘s and r‘s,
where b represents a blue bead and r represents a red one, as follows:
brbrrrbbbrrrrrbrrbbrbbbbrrrrb .

Suppose you are to break the necklace at some point, lay it out straight, and
then collect beads of the same color from one end until you reach a bead of a
different color, and do the same for the other end (which might not be of the
same color as the beads collected before this).

Determine the point where the necklace should be broken so that the most
number of beads can be collected.

Example

For example, for the necklace in Figure A, 8 beads can be collected, with the
breaking point either between bead 9 and bead 10 or else between bead 24 and
bead 25.

In some necklaces, white beads had been included as shown in Figure B above.
When collecting beads, a white bead that is encountered may be
treated as either red or blue and then painted with the desired color
.
The string that represents this configuration can include any of the three
symbols r, b and w.

Write a program to determine the largest number of beads that can be
collected from a supplied necklace.

这一道题做了一整天,更郁闷的是对完答案发现自己的方法太复杂了

我总是想着先把整个项链都染色成 red 或 blue 然后把每一段的相同颜色串的数量数出来 实际上可以每次只考虑一个缺口位置的局部信息就好了
 不需要提前染色 也不需要将整个项链的所有相同颜色玻璃串的个数存起来 因为存起来后 对于rwb bwr的情况还是要单独分析

用到了一些小技巧:

1.环装一定会用到mod 不过一般都是数字超过了范围用模电 这个项链可能数到-1 、-2 需要自己定义一个新的有负数的mod 或者 把信息存储两遍这样
可以在第一遍存储的最后可以直接通过加法读取下一个存储的起始的玻璃珠信息

答案:思路最清楚的代码


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

#define MAXN 400

char necklace[MAXN];
int len;

/*
* Return n mod m. The C % operator is not enough because
* its behavior is undefined on negative numbers.
*/
int
mod(int n, int m)
{
while(n < 0)
n += m;
return n%m;
}

/*
* Calculate number of beads gotten by breaking
* before character p and going in direction dir,
* which is 1 for forward and -1 for backward.
*/
int
nbreak(int p, int dir)
{
char color;
int i, n;

color = ‘w‘;

/* Start at p if going forward, bead before if going backward */
if(dir > 0)
i = p;
else
i = mod(p-1, len);

/* We use "n<len" to cut off loops that go around the whole necklace */
for(n=0; n<len; n++, i=mod(i+dir, len)) {
/* record which color we‘re going to collect */
if(color == ‘w‘ && necklace[i] != ‘w‘)
color = necklace[i];

/*
* If we‘ve chosen a color and see a bead
* not white and not that color, stop
*/
if(color != ‘w‘ && necklace[i] != ‘w‘ && necklace[i] != color)
break;
}
return n;
}

void
main(void)
{
FILE *fin, *fout;
int i, n, m;

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

fscanf(fin, "%d %s", &len, necklace);
assert(strlen(necklace) == len);

m = 0;
for(i=0; i<len; i++) {
n = nbreak(i, 1) + nbreak(i, -1);
if(n > m)
m = n;
}

/*
* If the whole necklace can be gotten with a good
* break, we‘ll sometimes count beads more than
* once. this can only happen when the whole necklace
* can be taken, when beads that can be grabbed from
* the right of the break can also be grabbed from the left.
*/
if(m > len)
m = len;

fprintf(fout, "%d\n", m);
exit (0);
}

动态规划的答案我没怎么看还:


#include <stdio.h>
#include <string.h>
#include <algorithm>

using namespace std;

FILE *in,*out;

int main () {
in = fopen("beads.in", "r");
out = fopen ("beads.out", "w");

int n;
char tmp[400], s[800];
fscanf(in, "%d %s", &n, tmp);

strcpy(s, tmp);
strcat(s, tmp);

int left[800][2], right[800][2];
left[0][0] = left[0][1] = 0;

for (int i=1; i<= 2 * n; i++){
if (s[i - 1] == ‘r‘){
left[i][0] = left[i - 1][0] + 1;
left[i][1] = 0;
} else if (s[i - 1] == ‘b‘){
left[i][1] = left[i - 1][1] + 1;
left[i][0] = 0;
} else {
left[i][0] = left[i - 1][0] + 1;
left[i][1] = left[i - 1][1] + 1;
}
}

right[2 * n][0] = right[2 * n][1] = 0;
for (int i=2 * n - 1; i >= 0; i--){
if (s[i] == ‘r‘){
right[i][0] = right[i + 1][0] + 1;
right[i][1] = 0;
} else if (s[i] == ‘b‘){
right[i][1] = right[i + 1][1] + 1;
right[i][0] = 0;
} else {
right[i][0] = right[i + 1][0] + 1;
right[i][1] = right[i + 1][1] + 1;
}
}

int m = 0;
for (int i=0; i<2 * n; i++)
m = max(m, max(left[i][0], left[i][1]) + max(right[i][0], right[i][1]));
m = min(m, n);
fprintf(out, "%d\n", m);
fclose(in); fclose(out);
return 0;
}

简便的方案:


#include <iostream>
#include <fstream>
using namespace std;

int main() {
fstream input, output;
string inputFilename = "beads.in", outputFilename = "beads.out";
input.open(inputFilename.c_str(), ios::in);
output.open(outputFilename.c_str(), ios::out);

int n, max=0, current, state, i, j;
string s;
char c;

input >> n >> s;
s = s+s;
for(i=0; i<n; i++) {
c = (char) s[i];
if(c == ‘w‘)
state = 0;
else
state = 1;
j = i;
current = 0;
while(state <= 2) {
// dont go further in second string than starting position in first string
while(j<n+i && (s[j] == c || s[j] == ‘w‘)) {
current++;
j++;
} // while
state++;
c = s[j];
} // while
if(current > max)
max = current;
} // for

output << max << endl;
return 0;
} // main

我自己写的非常复杂 但至少还对了的代码:


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

#define MaxLength 350
typedef struct{
int color;
int num;
int type;
} Pos;

typedef struct {
int colorleft;
int colorright;
int location;
int length;
}RWB;

typedef struct {
int num;
int type;
}NUM;
enum Type{left, right};

int main()
{
FILE *in, *out;
int num, longgest = 0;
int countr = 0, countb = 0;
int tmp;
int length = 0;
int recordnum = 0, recorddnum = 0;
int i = 0, j;
int first = -1; //最小的记录点
char necklace[351];

in = fopen("beads.in", "r");
out = fopen("beads.out", "w");

fscanf(in, "%d", &length);
fscanf(in, "%s", necklace);

while(i < length) //得到项链长度
{
if(necklace[i] == ‘r‘)
countr++;
else if(necklace[i] == ‘b‘)
countb++;
i++;
}

if(countr == 0 || countb == 0)
{
fprintf(out ,"%d\n", length);
return 0;
}

Pos record[MaxLength];
RWB recordd[MaxLength];
i = 0;
while(i < length) //定位第一个left
{
if(necklace[i] != ‘w‘ && necklace[i+1] == ‘w‘)
{
first = i;
record[0].color = necklace[i];
record[0].num = i;
record[0].type = left;
recordnum++;
break;
}
i++;
}

if(first != -1)
{
for(i = first + 1 ; i != first; i = (i + 1) % length) //记录 bw wb rw wr的位置
{
if(necklace[i] != ‘w‘ && necklace[(i+1)%length] == ‘w‘)
{
record[recordnum].color = necklace[i];
record[recordnum].num = i;
record[recordnum].type = left;
recordnum++;
}
else if(necklace[i] == ‘w‘ && necklace[(i+1)%length] != ‘w‘)
{
record[recordnum].color = necklace[(i+1)%length];
record[recordnum].num = (i+1)%length;
record[recordnum].type = right;
recordnum++;
}
}

assert(recordnum % 2 == 0);
assert(record[recordnum-1].type == right);

for(i = 0; i < recordnum; i = i + 2) //根据记录信息 将 rw...wr 和 bw...wb的直接染色 将 rw..wb bw..wr的取出
{
assert((record[i].type == left && record[i+1].type == right));
if(record[i].color == record[i+1].color)
{
for(j = (record[i].num + 1)%length; j != record[i+1].num; j = (j + 1) % length)
{
necklace[j] = record[i].color;
}

}
else
{
recordd[recorddnum].colorleft = record[i].color;
recordd[recorddnum].colorright = record[i+1].color;
recordd[recorddnum].length = record[i+1].num - record[i].num - 1;
recordd[recorddnum].location = record[i].num;
recorddnum++;
}
}
}

//fprintf(out,"%s",necklace);

NUM record2[MaxLength];
int record2num = 0;
int numtmp = 1;
for(i = 0; i < length; i++) //统计项链相同颜色的个数 存放在数组中
{
if(necklace[i] == necklace[i+1] )
{
numtmp++;
}
else
{
record2[record2num].num = numtmp;
if(necklace[i] == ‘w‘)
record2[record2num].type = 1;
else
record2[record2num].type = 0;
numtmp = 1;
record2num++;
}
}
if(necklace[0] == necklace[length - 1]) //处理最后颜色与第一个颜色相同
{
record2num--;
record2[0].num += record2[record2num].num;
}
for(i = 0; i < record2num; i++)
{
record2[record2num + i] = record2[i];
}

int longgesttmp = 0;
int n;
for(i = 0; i < record2num ;i++) //根据存储的数组找最长链
{
n = 0;
j = i;
longgesttmp = 0;
while(1)
{
if(record2[j].type == 0)
n++;
if(n == 2 && j % record2num == i && record2[j].type == 1)
break;
if(n<3)
longgesttmp += record2[j].num;
else
break;
j++;
}
if(longgesttmp > longgest)
{
longgest = longgesttmp;
}
}

fprintf(out , "%d\n", longgest);

return 0;
}

【USACO】beads,码迷,mamicode.com

时间: 2024-08-09 06:34:18

【USACO】beads的相关文章

【USACO】第一章总结

做了大半个月,终于把第一章做完了 有的题遇到了不小的坎儿,看着网上一群高中生都做得那么好,心理还是有些小郁闷的.不禁感慨我过去的四年真是虚度啊.总结一下第一章学习到的知识吧. ①闰年判断 int isleapyear(int N) { if((N%100 != 0 && N%4 ==0) || (N%400 == 0)) return 1; else return 0; } 计算闰年日期时可以用两个数组存放每个月的时间 int Year[12] = {31, 28, 31, 30, 31,

【USACO】checker

一看题目 经典的8皇后问题 不过是皇后数量可变而已 不用想 回溯法. 需要个生成每次可选择序列的函数, 在存储可选择的序列时按照先大后小的顺序排的.这样每次找最小和去掉最小都很方便,只要有个记录数量的变量 每次减1就好了.  写完后,居然悲剧了. 在皇后数量达到13时, 在自己电脑上跑 内存溢出了 在评分系统上超时了.需要优化. #include <stdio.h> //k计算第几层从0开始 x已经摆好的位置 S存放产生的位置 l存放产生的数量 N一共有多少位置可以选择 int calcula

【USACO】milk3

倒牛奶的问题, 开始看感觉跟倒水的问题很像, 想直接找规律, 写个类似于循环取余的代码. 但后来发现不行,因为这道题有三个桶,水量也是有限制的.只好用模拟的方法把所有的情况都试一遍. 建一个state[21][21][21]的数组存储出现过的状态.对于遍历状态,对每一种状态, 分别采用六种处理方法,若有新状态出现这将新状态置为1,同时标记flag++:若所有循环之后,flag == 0, 就说明遍历完成了. 开始脑子抽筋了, 写了个多出口的程序, 显然是错的.如下: int mothersmil

【USACO】calfflac

关键:以回文中心位置为变量进行遍历 //必须把纯字母先提出来 否则肯能会出现错误 比如: lvlv= 在检查长度4时 lvlv认为不是回文 vlv=认为是回文 但实际上 lvl 出现的要更早一些 //判断回文的方法 可以输入字符串后 左右比较 或者分别正序 逆序 存储 判断是否相等 //我的思路不对 严重超时了 我是以长度为变量进行循环 对于每个长度 每一个不同起始点的序列都需要对 整个序列重新判断一次是否为回文 O(n^3) //答案中 以中心字母为变量进行循环 只需要对每一个字母做为中心变量

【USACO】Transformations

A square pattern of size N x N (1 <= N <= 10) black and white square tiles is transformed into another square pattern. Write a program that will recognize the minimum transformation that has been applied to the original pattern given the following l

【USACO】奶牛跑步2

P1443 - [USACO]奶牛跑步2 Description FJ的N(1 <= N <= 100,000)头奶牛们又兴高采烈地出来运动了!她们在一条无限长的小路上跑步,每头牛起跑的位置都不同,速度也不尽相同. 道路中划出了若干条跑道,以便她们能快速"超车",同一跑道中的任意两头牛都不会出现在相同的位置.不过FJ不愿让任何一头牛更换跑道或者调整速度,他想 知道如果让牛们跑足T(1 <= T <= 1,000,000,000)分钟的话,至少需要多少条跑道才能满

【USACO】ariprog

输入 : N  M 要找到长度为 N 的等差数列,要求数列中每个数字都可以表达成 a^2 + b^2 的和, 数字大小不超过M^2 + M^2 输出: 等差数列首元素 间隔 (多组答案分行输出) 解题思路:因为等差数列的数字都是平房和数  所以先生成所有的 从0 - M^2 + M^2的平方和数 去掉相同的并从小到大排序 然后对 所有间隔 . 首元素 做循环 判断能否找到以该首元素和间隔为条件的其他N-1个需要的数字 可以就存成答案: 提交后超时了.... test 5的时候 超了5s 正在想简

【USACO】Mother&#39;s Milk(搜索)

一开始还在想去重的问题,结果发现后台数据貌似没有重复的情况= = /* ID: 18906421 LANG: C++ PROG: milk3 */ #include<cmath> #include<cstdio> #include<vector> #include<algorithm> using namespace std; const int maxn = 25; int vis[maxn][maxn][maxn] = {0}; vector<in

【USACO】草地排水

Drainage Ditches 草地排水 usaco 4.2.1描述在农夫约翰的农场上,每逢下雨,Bessie最喜欢的三叶草地就积聚了一潭水.这意味着草地被水淹没了,并且小草要继续生长还要花相当长一段时间.因此,农夫约翰修建了一套排水系统来使贝茜的草地免除被大水淹没的烦恼(不用担心,雨水会流向附近的一条小溪).作为一名一流的技师,农夫约翰已经在每条排水沟的一端安上了控制器,这样他可以控制流入排水沟的水流量.农夫约翰知道每一条排水沟每分钟可以流过的水量,和排水系统的准确布局(起点为水潭而终点为小