POJ 1949 Chores(DAG上的最长路 , DP)

题意:

给定n项任务, 每项任务的完成用时t和完成每项任务前需要的k项任务, 求把所有任务完成的最短时间,有当前时间多项任务都可完成, 那么可以同时进行。

分析:

这题关键就是每项任务都会有先决条件, 要完成该项任务a必须先完成他的先决条件。

所以对于每个先决条件, 我们构建一条有向边到任务本身, 然后因为要求一个最小值, 按照最长路的方式松弛(dis[v] >= dis[u] + d, u是v的先决条件, d是v的完成时间,我们以边的终点完成时间作为边的权), 遇到没有出度的边记录答案。

方法一:最长路(2016ms)

#include<cstdio>
#include<iostream>
#include<queue>
#include<cstring>
#include<string>
#include<map>
#include<stack>
#include<vector>
#include<algorithm>
#include<cmath>
#define rep(i,a,b) for(int i = a; i < b; i++)
#define _rep(i,a,b) for(int i = a; i <= b; i++)
using namespace std;
const int inf = 1e9 + 7;
const int maxn = 10000 + 7;
int n, m;
vector<int> G[maxn];
int d[maxn]; //每条边以终点时间作为权值
int dis[maxn], vis[maxn];
int spfa(){
    int ans = -inf;
    fill(dis, dis+maxn, -inf); //求最长路
    queue<int> q;
    dis[0] = 0;
    q.push(0);//0点入队
    vis[0] = 1;
    while(!q.empty()){
        int u = q.front();
        for(int i = 0; i < G[u].size(); i++){
            int v = G[u][i];

            if(dis[v] < dis[u] + d[v]){
                dis[v] = dis[u] + d[v];//每条边以终点时间作为权值
                if(G[v].size() == 0) {//如果没有出边, 说明它不会对后面有任何影响, 它可能就是答案之一
                    ans = max(dis[v], ans);//直接更新答案
                    continue;
                }
                if(!vis[v]){
                    vis[v] = 1;
                    q.push(v);
                }
            }
        }
        vis[u] = 0;
        q.pop();
    }
    return ans;
}
int main()
{
    scanf("%d", &n);
    _rep(i,1,n){
        scanf("%d", &d[i]);
        int k, v;
        scanf("%d", &k);
        if(k == 0){
            G[0].push_back(i);//假设有一个0点连向所有入度为0的点, 方便处理
        }else{
            rep(j,0,k){
                scanf("%d", &v);
                G[v].push_back(i);
            }
        }
    }
    printf("%d\n",spfa() );
}

方法二 DP(344ms)

那么我们可以转化一下,假设该项任务有k项先决条件

dp[i]代表完成该项任务的最早时间, 最后找出最大的dp[i]就是答案。

#include<cstdio>
#include<iostream>
#include<queue>
#include<cstring>
#include<string>
#include<map>
#include<stack>
#include<vector>
#include<algorithm>
#include<cmath>
#define rep(i,a,b) for(int i = a; i < b; i++)
#define _rep(i,a,b) for(int i = a; i <= b; i++)
using namespace std;
const int inf = 1e9 + 7;
const int maxn = 10000 + 7;
int worktime[maxn], dp[maxn];
int n, m;
int main()
{
//    freopen("1.txt","r", stdin);
    scanf("%d", &n);
    int ans = -inf;
    _rep(i,1,n){
        scanf("%d", &worktime[i]);//工作时间
        int k, v;
        scanf("%d", &k);
        if(k == 0){
            dp[i] = worktime[i];
        }else{
            rep(j,0,k){
                scanf("%d", &v);
                dp[i] = max(dp[i] , dp[v] + worktime[i]);//找出最晚的先决条件
            }
        }
        ans = max(ans, dp[i]);
    }
    printf("%d\n", ans );
}

原文地址:https://www.cnblogs.com/Jadon97/p/8359578.html

时间: 2024-10-09 19:55:39

POJ 1949 Chores(DAG上的最长路 , DP)的相关文章

NYOJ_矩形嵌套(DAG上的最长路 + 经典dp)

本题大意:给定多个矩形的长和宽,让你判断最多能有几个矩形可以嵌套在一起,嵌套的条件为长和宽分别都小于另一个矩形的长和宽. 本题思路:其实这道题和之前做过的一道模版题数字三角形很相似,大体思路都一致,这道题是很经典的DAG上的最长路问题,用dp[ i ]表示以i为出发点的最长路的长度,因为每一步都只能走向他的相邻点,则 d[ i ]  = max(d[ j ] + 1)这里 j 是任意一个面积比 i 小的举行的编号. 下面的代码中附带了最小字典序最长路打印的问题,我们找到第一个路径最长的 i,往后

uva103(最长递增序列,dag上的最长路)

题目的意思是给定k个盒子,每个盒子的维度有n dimension 问最多有多少个盒子能够依次嵌套 但是这个嵌套的规则有点特殊,两个盒子,D = (d1,d2,...dn) ,E = (e1,e2...en) 只要盒子D的任意全排列,小于盒子E,那么就说明 盒子D能放入盒子E中,其实就是将两个盒子的维度排序,如果前一个盒子的维度依次小于后一个盒子,那么就说明前一个盒子能放入后一个盒子中 这个题目能够转化为最长递增子序列. 首先将盒子的维度从小到大排序,然后将k个盒子,按照排序后的第一维度从小到大排

hdu 1224(动态规划 DAG上的最长路)

Free DIY Tour Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 5815    Accepted Submission(s): 1855 Problem Description Weiwei is a software engineer of ShiningSoft. He has just excellently fulfi

HDU 3249 Test for job (有向无环图上的最长路,DP)

 解题思路: 求有向无环图上的最长路,简单的动态规划 #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <algorithm> #include <vector> #include <cmath> #define LL long long using namespace std; const int

hdu 1224 Free DIY Tour(最长路/dp)

http://acm.hdu.edu.cn/showproblem.php?pid=1224 基础的求最长路以及记录路径.感觉dijstra不及spfa好用,wa了两次. #include <stdio.h> #include <algorithm> #include <set> #include <map> #include <vector> #include <math.h> #include <string.h> #

[POJ3249]Test for Job [拓扑排序+DAG上的最长路径]

给定一张带点权的DAG 求一条入度为0节点到出度为0节点的最长路 把点权转化为边权(同时多源转化成单源):边u->v的权值为W[v],这样入度为0的节点权值会被遗漏,新开一个点0向入度为0的点u连有向边,权值为W[u],这样就只有0是入度为0的点了. 先进行拓扑排序,再利用DAG拓扑排序后的特性求出最长路径 1 #include <iostream> 2 #include <algorithm> 3 #include <cstring> 4 #include &l

Educational CF # 17 C 二分,字符串 D 最长路,dp

Educational Codeforces Round 17 C. Two strings 题意:两个字符串A,B,从B中删除尽可能少的子串,要使得B剩下的字符串是A的子序列,输出B剩下的字符串.(注意子串与子序列区别) 总结:看了某神犇的代码,不太理解..官方题解:不要去想从B中删掉子串,应该想,从B的左端取出一段子串,再从右端取出一段子串. // Educational Codeforces Round 17 C #include<bits/stdc++.h> using namespa

DAG上动态规划

很多动态规划问题都可以转化为DAG上的最长路,最短路,或路径计数问题. 硬币问题: 有N中硬币,面值分别为v1,v2,v3,……vn,每种都无穷多,给定非负整数S,可以选用多少个硬币,使他们的总和恰好为S.输出硬币数目的最小值和最大值. 解:每种面值看作一个点,表示:还需要凑足的面值.则开始状态为S,目标状态为0:若当前状态为i,当使用硬币j后,状态转为i-v[j]. 代码说明好了. 1 #include <iostream> 2 #include <cstdio> 3 #incl

DP入门(2)——DAG上的动态规划

有向无环图(DAG,Directed Acyclic Graph)上的动态规划是学习动态规划的基础.很多问题都可以转化为DAG上的最长路.最短路或路径计数问题. 一.DAG模型 [嵌套矩形问题] 问题:有n个矩形,每个矩形可以用两个整数a.b描述,表示它的长和宽.矩形X(a , b)可以嵌套在矩形Y(c , d)中当且仅当a<c,b<d,或者b<c,a<d(相当于把矩形X旋转90°).例如(1,5)可以嵌套在(6, 2)内,但不能嵌套在(3, 4)内.你的任务是选出尽可能多的矩形排