[状压DP]LibreOJ #6177. 「美团 CodeM 初赛 Round B」送外卖2 题解
来源:互联网 发布:java九大排序算法 编辑:程序博客网 时间:2024/06/04 13:35
(传送门)
题目大意
已知一个有n个节点m条边的有向图,给出k个任务,每个任务从Li开始,到Ri结束,要求在Si接收货物并且在时间结束前Ti送达。(领货和交货不需要消耗时间),问最多能做多少个任务(注意,可以有多个货物在手上)。
解题分析
考虑到这题的k比较小,可以DFS或者是状压DP,DFS没什么好想法,那么开始思考状压DP。
如果求最多能完成几个任务有点烦,可以将货物情况进行状压,由于每个货物可能未送达,已到,又或者还没拿到,所以这道题是3进制存储状态。对于每位i,表示第i个节点的状态:0为未接收,1为已接收未送达,2为已送达。
因为如果送的时间越早,有更多的时间完成后面的任务,所以需要完成当前状态时所耗费的时间越少。但是完成这个状态时在哪?很明显完成状态时所在节点也要枚举。
但是如果走到一个节点然后什么都不会发生,那就是浪费时间。所以其实在枚举状态j之后不是枚举节点i而是任务i,这样只需传到s[i]或t[i],减少转移状态(因为很明显求最短路后直接连起来就行了,无需中间状态)。
上面有点乱,可以直接看转移方程(或者代码),比较清晰:
如果当前是要接收这个货物i(对应三进制数位置为1)
如果当前是要送达这个货物i(对应三进制数位置为2)
复杂度
时间:
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int maxs=59049;int n,e,k,ans,INF,dis[25][25],a[15],p[15],s[15],t[15],L[15],R[15],f[25][maxs+5];int po_s(int x,int len){return x/p[len]%3;}int _count(int x){int tot=0;for (int i=0;i<k;i++) tot+=(po_s(x,i)==2);/* printf("%d %d\n",x,tot); */return tot;}inline void readi(int &x){ x=0; char ch=getchar(); while ('0'>ch||ch>'9') ch=getchar(); while ('0'<=ch&&ch<='9') {x=x*10+ch-'0'; ch=getchar();}}void Flyod(){ for (int i=1;i<=n;i++) dis[i][i]=0; for (int t=1;t<=n;t++) for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) if (dis[i][j]>dis[i][t]+dis[t][j]) dis[i][j]=dis[i][t]+dis[t][j];}int main(){ freopen("c.in","r",stdin); freopen("c.out","w",stdout); readi(n); readi(e); readi(k); ans=0; memset(dis,63,sizeof(dis)); for (int i=1,x,y,z;i<=e;i++){ readi(x); readi(y); readi(z); if (z<dis[x][y]) dis[x][y]=z; } for (int i=0;i<k;i++) {readi(s[i]); readi(t[i]); readi(L[i]); readi(R[i]);} Flyod(); p[0]=1; for (int i=1;i<=k;i++) p[i]=p[i-1]*3; memset(f,63,sizeof(f)); INF=f[0][0]; f[1][0]=ans=0; for (int j=1;j<p[k];j++) for (int i=0,q;i<k;i++){ q=po_s(j,i); switch (q){ case 1: for (int u=1;u<=n;u++) if (f[u][j-p[i]]<INF&&f[u][j-p[i]]+dis[u][s[i]]<=R[i]) f[s[i]][j]=max(L[i],min(f[s[i]][j],f[u][j-p[i]]+dis[u][s[i]])); break; case 2: for (int u=1;u<=n;u++) if (f[u][j-p[i]]<INF&&f[u][j-p[i]]+dis[u][t[i]]<=R[i]) f[t[i]][j]=min(f[t[i]][j],f[u][j-p[i]]+dis[u][t[i]]); break; } } /*for (int i=1;i<p[k];i++) for (int j=1;j<=n;j++) printf("%d %d %d\n",i,j,f[i][j]);*/ for (int j=1;j<p[k];j++) for (int i=1;i<=n;i++) if (f[i][j]<INF) ans=max(ans,_count(j)); printf("%d",ans); return 0;}
阅读全文
0 0
- [状压DP]LibreOJ #6177. 「美团 CodeM 初赛 Round B」送外卖2 题解
- 【LibreOJ】6177 「美团 CodeM 初赛 Round B」送外卖2 状压DP
- 【状压DP】LOJ#6177. 「美团 CodeM 初赛 Round B」送外卖2
- 【状压DP】LibreOJ6177(美团 CodeM 初赛 Round B)[送外卖2]题解
- #6177. 「美团 CodeM 初赛 Round B」送外卖2
- LibreOJ6177(美团 CodeM 初赛 Round B)[送外卖2]--状压DP
- [期望DP] LibreOJ #6178. [美团 CodeM 初赛 Round B] 景区路线规划 题解
- LibreOJ 6178「美团 CodeM 初赛 Round B」景区路线规划
- CodeM美团点评编程大赛初赛B轮 B.送外卖2【三进制状压Dp】
- CodeM美团点评编程大赛初赛B轮 B.送外卖2 三进制状压DP
- LibreOJ 6162 「美团 CodeM 初赛 Round A」身体训练
- 「美团 CodeM 初赛 Round B」子串
- 【期望DP】LibreOJ6178(美团 CodeM 初赛 Round B)[景区路线规划]题解
- 【期望DP】LOJ#6178. 「美团 CodeM 初赛 Round B」景区路线规划
- 美团codeM预赛B 送外卖2
- #6175. 「美团 CodeM 初赛 Round B」黑白树
- 「美团 CodeM 初赛 Round A」身体训练
- 「美团 CodeM 初赛 Round A」倒水
- C/C++中可变参数的原理
- 你所不知道的 CSS 滤镜技巧与细节
- 56. Merge Intervals && 57. Insert Interval
- Qt之QSS(Q_PROPERTY-自定义属性)
- 字符串转换为数字
- [状压DP]LibreOJ #6177. 「美团 CodeM 初赛 Round B」送外卖2 题解
- c语言中逗号运算符和逗号表达式
- Spring框架总结
- 趣图丨程序员的专属菜单
- 汉诺塔递归实现原理
- 在Anaconda中随意更改python版本和其他相关包版本的使用经验!
- python包:glob用法
- 十大要避免的Ext JS开发方法
- C++容器类——沉寂的孤城