Milking Cows问题 这是ACM得一道试题,我编写的代码,实在找不出毛病了,希望大神指点。问题可以百度。

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Milking Cows问题 这是ACM得一道试题,我编写的代码,实在找不出毛病了,希望大神指点。问题可以百度。相关的知识,希望对你有一定的参考价值。

#include<iostream>
using namespace std;
int main()

int **m;
int *max;///max【i】记录前面的奶农到第i的奶农的持续工作时间
int max2=0;
int n;
cin>>n;
m=new int*[n];
max=new int[n];
int i,j;
for( i=0;i<n;i++)
m[i]=new int[2];
for( i=0;i<n;i++)
cin>>m[i][0]>>m[i][1];
for( i=0;i<n;i++) ////////////根据奶农开始工作时间进行排序
for( j=1;j<n-i;j++)

if(m[j][0]<m[j-1][0])

int temp1,temp2;
temp1=m[j-1][0];
temp2=m[j-1][1];
m[j-1][0]=m[j][0];
m[j-1][1]=m[j][1];
m[j][0]=temp1;
m[j][1]=temp2;



max[0]=m[0][1]-m[0][0]; ///第一个奶农的持续工作时间自然是他自己的工作时间
for( i=1;i<n;i++)

if(m[i][0]<=m[i-1][1])
max[i]=max[i-1]+m[i][1]-m[i-1][1];
else
max[i]=m[i][1]-m[i][0];
if(m[i][0]-m[i-1][1]>max2)
max2=m[i][0]-m[i-1][1];


for( i=0;i<n;i++) ////对max进行排序
for( j=1;j<n-i;j++)

if(max[j]<max[j-1])

int temp;
temp=max[j-1];
max[j-1]=max[j];
max[j]=temp;



cout<<max[n-1]<<" "<<max2;
return 0;

参考技术A 分析:
农民1的时间区间为:[300,1000]
农民2的时间区间为:[700,1200]
农民3的时间区间为:[1500,2000]
合并区间可以得到[300,1200],[1500,2000]
显然合并后区间的长度中最大值便是我们所求的最长持续时间。这里是max900,500
所以区间的两两间的间隔中最大值便是我们所求的最长中断时间。这里是max300
所以我们只有获得一个合并后的区间,再求以上两个值的集合后取相应的最大值就可以得到本题的解。
农民的区间排列并非有序,农民2的区间可以是[100,500]。所以首先我们需要对区间左端进行升序排序。
对区间的右端排序之后,对于相邻的两个区间[a(n),b(n)]与[a(n+1),b(n+1)],由于a(n)<=a(n+1)(已知a(n)<=b(n)),
故这两个区间的关系只有包含,相交,以及无交集三个关系。可以得到
包含:a(n+1)<=b(n) b(n+1)<=b(n)
相交:a(n+1)<=b(n)
无交集:a(n+1)>b(n)
遍历两次依据这三种关系,做适当操作即可将合并区间。
合并之后,除去那些无用的区间(事实上在合并的时候可以将那些被合并的区间中后一个区间长度变为0),获得一个新的区间列表,在这个新的区间列表找寻最大长度区间和最大中断区间间隔即可获得解。
具体d的c++代码如下:
#include<iostream>
#include<fstream>
#include<string>
using namespace std;
bool IsInRange(int a,int b,int n);
int main()

ifstream fin ("milk2.in");
ofstream fout ("milk2.out");
int n;
int max_c=0; // max continuous time
int max_b=0; // max break time
int a[5000][2];
int fa[5000][2];//过滤a后的数组
int len=0;
int c=0;
int b=0;
fin>>n;
for(int i=0;i<n;i++)//获得输入

fin>>a[i][0]>>a[i][1];

//先排序,以farm开始的时间即区间的左端点从小到大排序
for(int i=1;i<n;i++)

int a1,a2;
if(a[i][0]<a[i-1][0])

int k=i;
while(a[k][0]<a[k-1][0])//swap,交换

a1=a[k][0];
a2=a[k][1];
a[k][0]=a[k-1][0];
a[k][1]=a[k-1][1];
a[k-1][0]=a1;
a[k-1][1]=a2;
k--;
if(k==0)
break;



//合并1.交 2.包含 3.无交集
for(int i=0;i<n-1;i++)

for(int j=i+1;j<n;j++)

int s0=a[i][0]; //初始化两个区间
int e0=a[i][1];
int s1=a[j][0];
int e1=a[j][1];
if(IsInRange(s0,e0,s1))//判断左端点

if(IsInRange(s0,e0,e1))//判断右端点,包含关系,合并区间

a[j][0]=a[i][1]; //[3,9],[4,7]->[3,9][3,3]
a[j][1]=a[i][0];
a[j][0]=a[i][0];

else//交集

a[i][1]=a[j][1]; //[3,5],[4,7]->[3,7],[3,3]
a[j][0]=a[i][0];
a[j][1]=a[i][0];


else //无交集

break;



len=0;
for(int i=0;i<n;i++)//移除[3,3],[12,12]这样的无效项

max_c=a[0][1]-a[0][0];//第一个区间的长度
max_b=0; //初始间隔为0
int k=0;
for(int i=0;i<n-1;i++)

int c=fa[i+1][1]-fa[i+1][0];//区间长度
int b=fa[i+1][0]-fa[i][1];//区间间隔
if(c>max_c) //保留区间长度的最大值

max_c=c;

if(b>max_b) //保留区间间隔的最大值

max_b=b;
b=0;


fout<<max_c<<" "<<max_b<<endl;
return 0;

bool IsInRange(int a,int b,int n) //判断n是否属于[a,b]

if(n>=a&&n<=b)

return true;

else

return false;


以上算法可以优化,不用合并区间,直接寻找解也可以。
代码如下:
#include<iostream>
#include<fstream>
#include<string>
using namespace std;
bool IsInRange(int a,int b,int n);
void QuikSort(int a[][2],int left,int right);
int main()

ifstream fin ("milk2.in");
ofstream fout ("milk2.out");
//ofstream ftest("m.out");
int n;
int max_c=0; // max continuous time
int max_b=0; // max break time
int a[5000][2];
int len=0;
int c=0;
int b=0;
fin>>n;
fin>>a[0][0]>>a[0][1];
for(int i=1;i<n;i++)//获得输入

fin>>a[i][0]>>a[i][1];

QuikSort(a,0,n-1);
int cur[2];
cur[0]=a[0][0];
cur[1]=a[0][1];
max_c=a[0][1]-a[0][0];//第一个区间的长度
max_b=0; //初始间隔为0
for(int i=1;i<n;i++) //寻找最大最小值

if(a[i][0]>cur[1])

b=a[i][0]-cur[1];
if(b>max_b) max_b=b;
c=cur[1]-cur[0];
if(c>max_c) max_c=c;
cur[0]=a[i][0];
cur[1]=a[i][1];

else
//3,67, 4,87, 5,77 3->87 3->87
if(a[i][1]>cur[1]) cur[1]=a[i][1];


fout<<max_c<<" "<<max_b<<endl;
return 0;

void QuikSort(int a[][2],int left,int right)//快速排序

if(left<right)

int s=a[left][0]; //哨兵,即参考值X
int s1=a[left][1];
int i=left+1;
int j=right;
while(true)

while(a[i][0]<s&&i<right)
i++;
while(a[j][0]>s&&j>=0)
j--;
if(i>=j) break;
int a1,a2;
a1=a[i][0];
a2=a[i][1];
a[i][0]=a[j][0];
a[i][1]=a[j][1];
a[j][0]=a1;
a[j][1]=a2;
i++;
j--;

a[left][0]=a[j][0];
a[left][1]=a[j][1];
a[j][0]=s;
a[j][1]=s1;
QuikSort(a,left,j-1);
QuikSort(a,j+1,right);


bool IsInRange(int a,int b,int n) //判断n是否属于[a,b]

if(n>=a&&n<=b)

return true;

else

return false;

追问

我想知道我的算法bug在哪里?

[USACO1.2]挤牛奶Milking Cows

题目描述

三个农民每天清晨5点起床,然后去牛棚给3头牛挤奶。第一个农民在300秒(从5点开始计时)给他的牛挤奶,一直到1000秒。第二个农民在700秒开始,在 1200秒结束。第三个农民在1500秒开始2100秒结束。期间最长的至少有一个农民在挤奶的连续时间为900秒(从300秒到1200秒),而最长的无人挤奶的连续时间(从挤奶开始一直到挤奶结束)为300秒(从1200秒到1500秒)。

你的任务是编一个程序,读入一个有N个农民(1 <= N <= 5000)挤N头牛的工作时间列表,计算以下两点(均以秒为单位):

最长至少有一人在挤奶的时间段。

最长的无人挤奶的时间段。(从有人挤奶开始算起)

输入输出格式

输入格式:

Line 1:

一个整数N。

Lines 2..N+1:

每行两个小于1000000的非负整数,表示一个农民的开始时刻与结束时刻。

输出格式:

一行,两个整数,即题目所要求的两个答案。

输入输出样例

输入样例#1:
3
300 1000
700 1200
1500 2100
输出样例#1:
900 300


题解:
  这个题目还是比较水的吧,设dp[i]表示选以i结尾的物品的最大价值。
  那么dp[i]=max(dp[j]+v[i])(l[i]-r[j]>=休息时间)。

代码:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
#define MAXN 2000
#define ll long long
using namespace std;
struct qvjian{
    int l,r,v;
    void read(){
        scanf("%d%d%d",&l,&r,&v);
    }
}a[MAXN*2];
ll dp[MAXN];
int h,n,k;

bool cmp(qvjian x,qvjian y){
    return x.r<y.r;
}

int main()
{
    scanf("%d%d%d",&h,&n,&k);
    for(int i=1;i<=n;i++) a[i].read();
    sort(a+1,a+n+1,cmp);
    memset(dp,0,sizeof(dp));
    a[0].r=-(1<<30);
    for(int i=1;i<=n;i++){
        for(int j=i-1;j>=0;j--){
            if(a[i].l-a[j].r>=k)
                dp[i]=max(dp[i],dp[j]+a[i].v);
        }
    }
    ll ans=0;
    for(int i=1;i<=n;i++) ans=max(ans,dp[i]);
    printf("%lld\n",ans);
    return 0;
}

 

以上是关于Milking Cows问题 这是ACM得一道试题,我编写的代码,实在找不出毛病了,希望大神指点。问题可以百度。的主要内容,如果未能解决你的问题,请参考以下文章

Usaco 1.2.1 Milking Cows

Milking Cows 挤牛奶 USACO 排序 模拟

CodeForces 384C Milking cows

USACO 1.2 Milking Cows (枚举)

[USACO1.2]挤牛奶Milking Cows

USACO SECTION1 2.1 Milking Cows 简单贪心