USACO 1.2.1 Milking Cows (80 points)

In short: In order to save time, I opened a lot of arrays to save some of the amount that I need to use, probably to deal with the import time over and over. At that time, I vaguely felt that this was buried instability. I tested it for a long time, and there were always four data points that couldn't pass. Finally, I tried with the test data, and it turned out that the array was not big enough. I set two global variables to control the maximum time array and the maximum number of farmers. How could I remember the difference between MAXN and MAXT during the process of modifying the program?

For this question, I think we can start with the simplest idea, and then constantly adjust, so that the program can handle various special situations.

Assuming there is such a timetable, the state at each moment is represented by a number: when someone is working, it is recorded as 1, and when no one is working, it is recorded as 0. You can easily generate such a table based on the input information. In this case, you can already handle some basic situations, such as one person starting from 2100 to 2300, and another person from 3000 to 3200. Print out this table, the continuous interval of 1 means that they have someone working, and 0 means that no one is working. We calculate continuous work or continuous idle by counting the number of 1 and 0.

Think about it carefully, our watch has some defects, because there will be some special circumstances, such as one person working from 2100 to 2200, and another person from 2201 to 2300. Simply observing our watch, the time periods of these two people are completely connected, and the question requires us to disconnect it. Therefore, we need to deal with this situation specially. I think we can use 9 instead of 1 for the first number of the person behind. This will result in a table similar to 0000111111119111110000, and 9 distinguishes the work of the two people before and after. Open. (You need a way to compare whether the start of the next person is immediately followed by the end of the previous person, you can use a boolean array to mark the time)

There are still some problems with this, because if one person A works from 2000 to 2400, another person B works from 2100 to 2200, and another person C works from 2101 to 2300. The working hours of A include B and C, and the 9 we set when separating BC caused this situation, similar to 1111111111911111111111, but in fact this whole line is the continuous work of A and should not be disconnected in the middle . Our counting module can't handle this problem, so we might as well set all the middle part of a person's working time to 1 after setting 9 last time, so that the 9 in A will be overwritten.

There are also some things to consider, such as how to calculate the free time immediately after the end, how to correctly output the situation where there is no free time in the middle, and solve these problems to solve this problem.

package milkingCows;

import java.util.Scanner;

//工作区间设为1
//区分出结束后立刻开始新一轮的情况
//记录用数组  时间线 开始时间 结束时间
public class Main {
    
    
	final static int MAXN= 5010;
	final static int MAXT= 1000000;
	//状态1 0 9
	static public int[] timeLine= new int[MAXT];
	//标记某时间是开始还是结束
	static public boolean[] staTime= new boolean[MAXT];
	static public boolean[] endTime= new boolean[MAXT];
	static public int n;
	static public int earlyStart= MAXT+10;
	static public int lateEnd= 0;
	//用来把一个人的工作区间置1
	static public int[] staMemo= new int[MAXN];
	static public int[] endMemo= new int[MAXN];
	
	public static void main(String[] args) {
    
    

		//输入数据
		Scanner console= new Scanner(System.in);
		n= console.nextInt();
		int sta, end;
		
		for(int i=0; i<n; i++) {
    
    
			sta= console.nextInt();
			end= console.nextInt();
			//得到时间范围
			if(sta<earlyStart) earlyStart= sta;
			if(end>lateEnd) lateEnd= end;
			
			staTime[sta]= true;
			endTime[end]= true;
			staMemo[i]= sta;
			endMemo[i]= end;
			
			
			///工作区间设为1
			for(int j=sta; j<=end; j++) {
    
    
				timeLine[j]= 1;
			}
		}
		
		//将结束后立刻开始的情况开头标注9
		for(int i=earlyStart; i<=lateEnd; i++) {
    
    
			if(endTime[i]==true&&staTime[i+1]== true)timeLine[i+1]=9;
		}
		
		//防止中间区间被注9
		for(int i=0; i<n; i++) {
    
    
			for(int j=staMemo[i]+1; j<=endMemo[i]; j++) {
    
    
				timeLine[j]= 1;
			}
		}
		
		
		
		//计算连续长度
		int maxBusy=0, maxFree= 0;
		boolean everFree= false;//用于标记有没有中间断开过 处理输出maxFree导致的未断开也为1的情况
		for(int i=earlyStart; i<=lateEnd;i++) {
    
    
			int j= i;
			int tempLen=0;
			switch(timeLine[i]) {
    
    
				case 1:
					while(timeLine[j]==1)j++;
					tempLen= j-i;
					if(tempLen> maxBusy)maxBusy= tempLen;
					i= j-1;//跨过为1的区域,回退1位因为for循环还会再+1;
					break;
				case 9:
					everFree= true;
					//处理工作
					j= i+1;//不可能只有9后面没有1,所以可以把i放在9后面
					while(timeLine[j]==1)j++;
					tempLen= j-i;
					if(tempLen> maxBusy)maxBusy= tempLen;
					i= j-1;
					break;
				case 0:
					everFree= true;
					while(timeLine[j]==0&&j<lateEnd)j++;
					tempLen= j-i;
					if(tempLen> maxFree)maxFree= tempLen;
					i= j-1;
					break;
				default:
					System.out.println("ERROR");
					
			}
		}
		
		if(everFree== false) maxFree= -1;//处理未曾空闲的情况
		System.out.println((maxBusy-1) +" "+ (maxFree+1));
		
		
		for(int j=earlyStart; j<=lateEnd; j++) {
    
    
			System.out.print(timeLine[j]);
		}
	}
}

Guess you like

Origin blog.csdn.net/roswellnotfound/article/details/108810001