尼克的任务
作者:互联网
题目描述:时间1-n范围内,有k个任务,起始和终止时间固定,员工在空闲时如果有任务就必须工作,
但是如果有多个任务就可以自己选择,求最大休闲时间.
思路:
方法1:dp倒着推,dp[i]表示在i时间点开始工作的最大休闲时间,
如果i是某些工作的起始点,则必须要工作,从这些工作中的终止时间t中找最小的工作时间,
dp[i]=min(dp[i],dp[t]+t-i);
如果i不是工作的起始点,则dp[i]=dp[i+1],即这一分钟不需要工作
输出dp[1]即可
code:
#include<bits/stdc++.h> using namespace std; const int maxn = 100100; const int inf = 0x3f3f3f3f; typedef long long ll; vector<int>work[maxn]; int f[maxn]; int n, k; int main() { //freopen("test.txt", "r", stdin); scanf("%d%d", &n, &k); for (int i = 1; i <= k; i++) { int s, t; scanf("%d%d", &s, &t); work[s].push_back(t); } memset(f, 0x3f, sizeof(f)); f[n+1] = 0; for (int i = n; i >= 1; i--) { if (work[i].empty()) {//没有工作 f[i] = f[i + 1]; } else {//有工作必须要开始工作 for (int x : work[i]) { f[i] = min(f[i], f[i + x] + x); } } } //总时长-最小工作时间 cout << n-f[1] << endl; return 0; }
方法2,最短路
我们把没一分钟看作一个点,工作时间就是起点与重点连边,权值为时间,
如果该点没有工作,则可以休息,与下一个点连权值为0的边,跑1-n的最短路即可得到最小工作时间t
n-t就是最长休息时间
code:
#include<bits/stdc++.h> using namespace std; const int maxn = 100100; const int inf = 0x3f3f3f3f; //之前少开了个0... typedef long long ll; struct edge { int f, t, dis, nxt; }e[maxn]; int hd[maxn], tot; void add(int f, int t, int dis) { e[++tot] = { f,t,dis,hd[f] }; hd[f] = tot; } int n, k; int dis[maxn], inque[maxn]; void spfa(int s) { queue<int>q; memset(dis, 0x3f, sizeof(dis)); dis[s] = 0; q.push(s); inque[s] = 1; while (!q.empty()) { int u = q.front(); q.pop(); inque[u] = 0; for (int i = hd[u]; i; i = e[i].nxt) { int v = e[i].t; if (dis[u] + e[i].dis < dis[v]) { dis[v] = dis[u] + e[i].dis; if (!inque[v]) { q.push(v); inque[v] = 1; } } } } } int main() { //freopen("test.txt", "r", stdin); scanf("%d%d", &n, &k); for (int i = 1; i <= k; i++) { int s, t; scanf("%d%d", &s, &t); add(s, s + t, t); } for (int i = 1; i <= n; i++) { if (!hd[i]) {//该点不需要工作 add(i, i + 1, 0); } } spfa(1); cout << n - dis[n + 1] << endl; return 0; }
标签:int,inque,工作,任务,maxn,尼克,dp,dis 来源: https://www.cnblogs.com/MYMYACMer/p/14798036.html