题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=108
题目大意:证明老鼠重量越重,速度越慢,给你一组老鼠的数据(包括重量和速度),要求输出满足前面条件的最长的子序列的老鼠编号
首先,按照老鼠的重量进行升序和速度的降序排列;
然后,根据动态方程求解
len[0]=1;len[i]=max{len[j]}+1 (0<=j<i)
最后,输出老鼠的编号顺序,为了能够输出顺序的编号,所以要给老鼠一个index和preIndex,最后输出时最好的方法是采用递归的方式
注意:
1.题目的结束是以文件结尾为结束符,在C和C++中是 EOF,但是在Java里文件结束是null,用Scanner和 BufferedReader 都可以,接着判断
(str = br.readLine()).equals("")就可以了;
或者是 !(str = sin.nextLine()).equals("")
2.使用BufferedReader每次读取的都是一行数据,这里我要得到的是以空格隔开来的两个数字,可以使用StringTokenizer,也可以使用Scanner,当然
这道题目其实使用String的各种操作也是可以实现的。
int w2=Integer.parseInt(str.substring(0, str.indexOf(" ")));//区别在这里
int s2=Integer.parseInt(str.substring(str.indexOf(" ")+1));
我的Java代码:【注意:结果是TLE,我实在是没有办法】
/**
* 修改排序方法,使用Collections.sort
* 修改设置preIndex的方法和输出方式
* 结果:TLE
*/
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Scanner;
public class ZOJ1108_4 {
public static int n;// 记录老鼠的数目
public static int[] len;// 记录以原序列中第i个老鼠结尾的最长的子序列
public static int maxlen, maxIndex;// 分别表示最大长度和最后的老鼠的index
public static ArrayList<Mouse> mice = new ArrayList<Mouse>();// 记住要new,不然会报空指针
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
n = 0;
String str;
while (!(str = br.readLine()).equals("")) {
Scanner sin = new Scanner(str);
int w = sin.nextInt();
int s = sin.nextInt();
Mouse m = new Mouse(n + 1, w, s);
n++;
mice.add(m);
}
Collections.sort(mice, new Comparator<Mouse>() {
public int compare(Mouse o1, Mouse o2) {
if (o1.weight > o2.weight) {
return 1;
} else if (o1.weight == o2.weight && o1.speed < o2.speed) {
return 1;
} else {
return -1;
}
}
});
dpSpeed();
System.out.println(maxlen);
output(maxIndex);
}
//根据老鼠的速度进行dp
private static void dpSpeed() {
len = new int[n];
int i, j, k;
maxlen = 0;
maxIndex = 0;
len[0] = 1;
mice.get(0).preIndex = 0;
for (i = 1; i < n; i++) {
len[i] = 1;
for (j = 0; j < i; j++) {
if (mice.get(i).speed < mice.get(j).speed
&& mice.get(i).weight > mice.get(j).weight) {
if (len[j] >= len[i]) {// 注意这里可以等于,也许刚好满足条件的那个就是长度为1[可以调试]
len[i] = len[j] + 1;
mice.get(i).preIndex = j;
}
}
}
}
for (k = 0; k < n; k++) {
if (len[k] > maxlen) {
maxlen = len[k];
maxIndex = k;
}
}
}
//用递归的方式输出
private static void output(int index) {
if(len[index]==1){
System.out.println(mice.get(index).index);
}else{
output(mice.get(index).preIndex);
System.out.println(mice.get(index).index);
}
}
}
class Mouse {
int index;// 记录该老鼠是原序列的第几位
int weight;// 记录重量和速度
int speed;
int preIndex;// 记录该老鼠在得到的序列中的上一个老鼠的index
public Mouse() {
}
public Mouse(int index, int weight, int speed) {
this.index = index;
this.weight = weight;
this.speed = speed;
}
}
换了一种方式,结果是RE,不知道哪里出错了
/**
* 修改排序方法,使用Collections.sort
* 修改设置preIndex的方法和输出方式
* 修改了得到输入数据的方法
* 结果:RE
*/
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Scanner;
public class Main{
public static int n;// 记录老鼠的数目
public static int[] len;// 记录以原序列中第i个老鼠结尾的最长的子序列的长度
public static int maxlen, maxIndex;// 分别表示最大长度和最后的老鼠的index
public static ArrayList<Mouse> mice = new ArrayList<Mouse>();// 记住要new,不然会报空指针
public static void main(String[] args){
Scanner sin=new Scanner(System.in);
n = 0;
String str;
while (!(str = sin.nextLine()).equals("")) {//利用nextLine方法也是可以的!
int w2=Integer.parseInt(str.substring(0, str.indexOf(" ")));//区别在这里
int s2=Integer.parseInt(str.substring(str.indexOf(" ")+1));
Mouse m = new Mouse(n + 1, w2, s2);
n++;
mice.add(m);
}
Collections.sort(mice, new Comparator<Mouse>() {
public int compare(Mouse o1, Mouse o2) {
if (o1.weight > o2.weight) {
return 1;
} else if (o1.weight == o2.weight && o1.speed < o2.speed) {
return 1;
} else {
return -1;
}
}
});
dpSpeed();
System.out.println(maxlen);
output(maxIndex);
}
//根据老鼠的速度进行dp
private static void dpSpeed() {
len = new int[n];
int i, j, k;
maxlen = 0;
maxIndex = 0;
len[0] = 1;
mice.get(0).preIndex = 0;
for (i = 1; i < n; i++) {
len[i] = 1;
mice.get(i).preIndex=i;
for (j = 0; j < i; j++) {
if (mice.get(i).speed < mice.get(j).speed
&& mice.get(i).weight > mice.get(j).weight) {
if (len[j] >= len[i]) {// 注意这里可以等于,也许刚好满足条件的那个就是长度为1[可以调试]
len[i] = len[j] + 1;
mice.get(i).preIndex = j;
}
}
}
}
for (k = 0; k < n; k++) {
if (len[k] > maxlen) {
maxlen = len[k];
maxIndex = k;
}
}
}
//用递归的方式输出
private static void output(int index) {
if(len[index]==1){//巧妙之处:最后的那个的len[]==1
System.out.println(mice.get(index).index);
}else{
output(mice.get(index).preIndex);
System.out.println(mice.get(index).index);
}
}
}
class Mouse {
int index;// 记录该老鼠是原序列的第几位
int weight;// 记录重量和速度
int speed;
int preIndex;// 记录该老鼠在得到的序列中的上一个老鼠的index
public Mouse() {
}
public Mouse(int index, int weight, int speed) {
this.index = index;
this.weight = weight;
this.speed = speed;
}
}
解题时我参考了网上一位同学的方法,很是不错啊,和我的差不多,不过输出我是参考他的
他用的是C++,顺利 AC ,我们的算法时间复杂度都是 O(n^2)。。。【详情可见我的博客中的另外一篇博文】
虽说还有一种更好的算法 O(nlog(n)),但是我怎么都没写出来,因为那个比较的方式太复杂了点
#include <iostream>
#include <algorithm>
#define MAX 1005
using namespace std;
struct Mice
{
int id;
int weight;
int speed;
int pre;
};
bool cmp(const Mice& a, const Mice& b)
{
if (a.weight < b.weight)
return true;
else if (a.weight == b.weight)
return a.speed > b.speed;
else
return false;
}
int num[MAX];
Mice mice[MAX];
void output(int);
int main()
{
int count = 0;
while (cin >> mice[count].weight >> mice[count].speed)
{
mice[count].id = count+1;
count++;
}
sort(mice, mice+count, cmp);
num[0] = 1;
mice[0].pre = 0;
for (int i = 1; i < count; i++)
{
num[i] = 1;
mice[i].pre = i;
for (int j = 0; j < i; j++)
{
if (mice[i].weight > mice[j].weight && mice[i].speed < mice[j].speed)
{
if (num[i] < num[j]+1)
{
num[i] = num[j]+1;
mice[i].pre = j;
}
}
}
}
int max_index = 0;
for (int i = 1; i < count; i++)
if (num[i] > num[max_index])
max_index = i;
cout << num[max_index] << endl;
output(max_index);
return 0;
}
void output(int index)
{
if (num[index] == 1)
cout << mice[index].id << endl;
else
{
output(mice[index].pre);
cout << mice[index].id << endl;
}
}