Description

Farmer John's family pitches in with the chores during milking, doing all the chores as quickly as possible. At FJ's house, some chores cannot be started until others have been completed, e.g., it is impossible to wash the cows until they are in the stalls. 



Farmer John has a list of N (3 <= N <= 10,000) chores that must be completed. Each chore requires an integer time (1 <= length of time <= 100) to complete and there may be other chores that must be completed before this chore is started. We will call these
prerequisite chores. At least one chore has no prerequisite: the very first one, number 1. Farmer John's list of chores is nicely ordered, and chore K (K > 1) can have only chores 1,.K-1 as prerequisites. Write a program that reads a list of chores from 1
to N with associated times and all perquisite chores. Now calculate the shortest time it will take to complete all N chores. Of course, chores that do not depend on each other can be performed simultaneously.

Input

* Line 1: One integer, N 



* Lines 2..N+1: N lines, each with several space-separated integers. Line 2 contains chore 1; line 3 contains chore 2, and so on. Each line contains the length of time to complete the chore, the number of the prerequisites, Pi, (0 <= Pi <= 100), and the Pi
prerequisites (range 1..N, of course). 

Output

A single line with an integer which is the least amount of time required to perform all the chores. 

       原题很简单,就是给定N个任务的时间和每个任务的前驱,求最短完成时间。
       初步研究,此题可以用最长路或是拓扑图来求解。

        vijos上有一道“休息中的小呆”,原理和此类似,然而那儿N<=100,N^3也绰绰有余,我就用floyd算法求出最长路并记录。然而现在的N<=10000,就连N^2也很危险。

        第一次,我打算也是用最长路求解。咨询过鼎神,目前只有SPFA可以有效处理最长路问题。方法就是把每条边的权值取相反数并做一遍最短路,答案再取相反数。因为N有10000而边数不知道,只好开一个边表记录。

代码一(SPFA最长路+边表优化)
#include<stdio.h>
#include<cstring>
using namespace std;
const long maxn=10001;const long INF=1;
bool flag[maxn];long cnt,i,n,j,xx,time,y,h,t,go,now,ans,tong;
long dis[maxn],begin[maxn],end[maxn],x[200*maxn];
struct arr{long l,r,s,next;}a[200*maxn];
void make_up(long l,long r,long v)
{
  a[++cnt].l=l;a[cnt].r=r;a[cnt].s=-v;a[cnt].next=-1;
  if (begin[l]==0) {begin[l]=cnt;end[l]=cnt;}
  else {a[end[l]].next=cnt;end[l]=cnt;}
}
int main()
{
  //freopen("chores.in","r",stdin);freopen("chores.out","w",stdout);
  scanf("%ld",&n);
  for (i=1;i<=n;i++)
  {
    scanf("%ld",&time);
    scanf("%ld",&xx);
    for (j=1;j<=xx;j++)
    {
      scanf("%ld",&y);
      make_up(y,i,time);
    }
    if (xx==0) make_up(0,i,time);
  }
  memset(flag,0,sizeof(flag));memset(dis,INF,sizeof(dis));
  h=0;t=1;x[1]=0;dis[0]=0;flag[0]=true;
  while (h<t)
  {
     now=x[++h];if (begin[now]==0) continue;i=begin[now];
     while (true)
     {
       go=a[i].r;
       if (dis[now]+a[i].s<dis[go])
       {
         dis[go]=dis[now]+a[i].s;
         if (!flag[go])
         {
           flag[go]=true;
           x[++t]=go;
         }
       }
       if (a[i].next==-1) break;i=a[i].next;
     }
     flag[now]=false;
  }
  for (i=1;i<=n;i++)
    if (-dis[i]>ans) ans=-dis[i];

  printf("%ld",ans);
  //scanf("%ld",&n);
  return 0;
}

然而交了之后一直TLE,自己下了个数据,发现最后一个点大概要13s左右!想不到在稠密图里,SPFA的效率又如此之低!(边表的常数又很大)无论怎么优化都不行!

       
       最后只能请教互联网了,没想到,其他大牛的代码如此简单!他们用了近似DP的算法!

代码二(据网上思路改编代码)
#include<stdio.h>
#include<cstring>
using namespace std;
long f[10001],n,i,j,max,ans,xx,y;
int main()
{
  //freopen("chores.in","r",stdin);freopen("chores.out","w",stdout);
  scanf("%ld",&n);
  for (i=1;i<=n;i++)
  {
    scanf("%ld",&f[i]);
    scanf("%ld",&xx);max=0;
    for (j=1;j<=xx;j++)
    {
      scanf("%ld",&y);
      if (f[y]>max) max=f[y];
    }
    f[i]+=max;
    if (f[i]>ans) ans=f[i];
  }
  printf("%ld",ans);
  //scanf("%ld",&n);
  return 0;
}

然而仔细一想,我发现他们只是钻了一个数据的漏洞——刚好数据的前后关系是由小到大的。思考了很长时间,我研究出了一个更加高级的算法——记忆化深搜+边表优化!


代码三(最终AC的代码)
#include<stdio.h>
#include<cstring>
using namespace std;
const long maxn=10001;const long INF=1;
long time[maxn],dp[maxn],begin[maxn],end[maxn],cnt,j,n,i,x,y,ans;
struct arr{long l,r,next;}a[200*maxn];
void make_up(long l,long r)
{
  a[++cnt].l=l;a[cnt].r=r;a[cnt].next=-1;
  if (begin[l]==0) {begin[l]=cnt;end[l]=cnt;}
  else {a[end[l]].next=cnt;end[l]=cnt;}
}
long go(long k)
{
  if (dp[k]>0) return dp[k];
  long now=begin[k];
  while (now>0)
  {
    long temp=go(a[now].r);
    dp[k]=(temp>dp[k])?temp:dp[k];
    now=a[now].next;
  }
  dp[k]+=time[k];
  return dp[k];
}
int main()
{
  //freopen("chores.in","r",stdin);freopen("chores.out","w",stdout);
  scanf("%ld",&n);
  for (i=1;i<=n;i++)
  {
    scanf("%ld",&time[i]);
    scanf("%ld",&x);
    for (j=1;j<=x;j++)
    {
      scanf("%ld",&y);make_up(i,y);
    }
    if (x==0) dp[i]=time[i];
  }
  for (i=1;i<=n;i++)
  {
    long temp=go(i);
    ans=(temp>ans)?temp:ans;
  }
  printf("%ld",ans);
  //scanf("%ld",&n);
  return 0;
}

希望众神牛看到后能够留言指导!


usaco 2002 月赛 Chores 题解的更多相关文章

  1. usaco 2002 月赛 Fiber Communications 题解

    Description Farmer John wants to connect his N (1 <= N <= 1,000) barns (numbered 1..N) with a ...

  2. POJ1944 Fiber Communications (USACO 2002 February)

    Fiber Communications 总时间限制:  1000ms 内存限制:  65536kB 描述 Farmer John wants to connect his N (1 <= N ...

  3. csu-2018年11月月赛Round2-div1题解

    csu-2018年11月月赛Round2-div1题解 A(2191):Wells的积木游戏 Description Wells有一堆N个积木,标号1~N,每个标号只出现一次 由于Wells是手残党, ...

  4. csu-2018年11月月赛Round2-div2题解

    csu-2018年11月月赛Round2-div2题解 A(2193):昆虫繁殖 Description 科学家在热带森林中发现了一种特殊的昆虫,这种昆虫的繁殖能力很强.每对成虫过x个月产y对卵,每对 ...

  5. usaco 2008 月赛 lites 开关灯 题解

      题目:     Farmer John尝试通过和奶牛们玩益智玩具来保持他的奶牛们思维敏捷. 其中一个大型玩具是 牛栏中的灯. N (2 <= N <= 100,000) 头奶牛中的每一 ...

  6. USACO全部月赛及GateWay数据

    月赛: 以07年open为例,网站如下 http://contest.usaco.org/OPEN07 其他的格式是http://contest.usaco.org/月份(月份的英文前三位,比如1月是 ...

  7. USACO Section 1.3 题解 (洛谷OJ P1209 P1444 P3650 P2693)

    usaco ch1.4 sort(d , d + c, [](int a, int b) -> bool { return a > b; }); 生成与过滤 generator&& ...

  8. 洛谷10月月赛II题解

    [咻咻咻] (https://www.luogu.org/contestnew/show/11616) 令人窒息的洛谷月赛,即将参加NOIp的我竟然只会一道题(也可以说一道也不会),最终145的我只能 ...

  9. BZOJ Lydsy5月月赛 ADG题解

    题目链接 BZOJ5月月赛 题解 好弱啊QAQ只写出三题 A 判断多干个数乘积是否是某个数的倍数有很多方法,比较常用的是取模,但这里并不适用,因为模数不定 会发现数都比较小,所以我们可以考虑分解质因子 ...

随机推荐

  1. 《Android进阶》之第三篇 深入理解android的消息处理机制

    Android 异步消息处理机制 让你深入理解 Looper.Handler.Message三者关系 android的消息处理机制(图+源码分析)——Looper,Handler,Message an ...

  2. (转ORCLE导入导出命令)

    oracle数据库导入导出命令! Oracle数据导入导出imp/exp 功能:Oracle数据导入导出imp/exp就相当与oracle数据还原与备份.   大多情况都可以用Oracle数据导入导出 ...

  3. Mysql数据库二进制安装

    MySQL数据库有四种安装方法: 源码包编译安装 RPM包安装 二进制文件安装 官方yum源安装 这里我们主要介绍二进制包的安装方法 在MySQL官网下载二进制包并且上传到服务器上 解压二进制包 [r ...

  4. Java内存数据模型

    本篇文章带来的是对Java内存数据模型的介绍,这对于我们深入理解Jvm虚拟机工作的原理和Java内存的划分大有裨益,好了,为了让我们理解的更为深刻,我们将会加入图片辅助的方法去理解. 本篇博文的目录: ...

  5. 提升单元测试体验的利器--Mockito使用总结

    为神马要使用Mockito? 在编写单元测试的时候,为了尽可能的保证隔离性,我们时常需要对某些不容易构造或者不容易获取或者对外部环境有依赖的对象,用一个虚拟的对象来创建以便于测试.假设你正在开发的的代 ...

  6. 平时常用的一些java方法,请留意

    平时常用的一些java方法,请留意. package com.util; import java.io.BufferedInputStream; import java.io.BufferedWrit ...

  7. tomcat服务器端口冲突问题的解决

    问题:tomcat服务器端口冲突 原因:服务器端口被占用:重启服务器之前原来的服务器没有关闭. 解决方案: 方案一:把占用的端口结束(方便快捷) 在cmd窗口输入命令 netstat -ano (查看 ...

  8. 利用React/anu编写一个弹出层

    本文将一步步介绍如何使用React或anu创建 一个弹出层. React时代,代码都是要经过编译的,我们很多时间都耗在babel与webpack上.因此本文也介绍如何玩webpack与babel. 我 ...

  9. JS中的函数传参

    前言: 函数分为有参有返回值,有参无返回值,无参无返回值,无参有返回值:那么对于无参数的函数你想使用函数的调用怎么办呢?如果你想封装一个代码,实现多种功能,但是形参大于实参或者实参大于形参又该如何?本 ...

  10. JS学习笔记——数组去重

    <script type="text/javascript"> //indexOf"是ECMAScript5方法,IE8以下不支持,需多写兼容低版本浏览器代码 ...