FJNU 1196 汪老司机(DP or 建图+最短路)
1196: 汪老司机
64-bit interger IO format: %lld Java class name: Main
注意:当汪老司机在家时,他可以选择两条路的任意一条路作为起点但不消耗他的变道次数
Input
对于每组样例:
第一行两个个数字n,k,分别表示道路路段的个数和能够变道的最多次数
第二行n个数字ai表示第一条道路不同路段的耗油量
第三行n个数字bi表示第二条道路不同路段的耗油量
( T <= 25, 1 <= n <= 10000, 0 <= k <= 10, 0 <= ai <= 1e9, 0 <= bi <= 1e9 )
Output
Sample Input
- 1
- 6 5
- 1 4 5 8 9 12
- 2 3 6 7 10 11
Sample Output
- 36
HINT
- 汪老司机行走的路线:a1 -> b2 -> a3 -> b4 -> a5 -> b6
题目链接:FJNU 1196
当时比赛的时候想到的是用最短路然而一直WA,后来下午补题室友提醒了一发说是用一个二维数组来做DP,然后突然就醒悟了……虽然我DP做的题不多,但是这种模型我见过很多,用DP[n][k]表示走过了前n条路变换k次车道的最小耗油量,然后……对!还差一个状态表示,那就再加一维变成DP[n][k][s]表示过了前n条路变换k次车道的最小耗油量且当前车子在s道上,然后很顺地写下来就1A了(鸡冻1s)。然而还是感觉我最短路的建模灰常完美没有任何问题啊,直到今晚写了个对拍发现了问题。
先说一下我当时最短路的建模吧,其实做过拆点题或者隐式图的题都很容易想到,虚拟一个原点S(0),每一个点都是一条边,那么显然每一个点周围应有两个虚拟节点,因此上半部分是$[1,n+1]$;同理下面的视为$[n+2,n*2+2]$,然后S连到上路的起点1,下路的起点n+2均为一条距离为0的边,那么转弯就可以看成是上面到点到下面的对称点之间的双向边,边权也显然均为0($i <=> i+n+1$),然后边里当然要加一个记录是否是变道路的变量flag,然后跑一个带限制的SPFA即可。
但是这样做是有问题的,比如这组数据
10
10 1
7 5 6 2 8 6 8 1 9 4
3 2 8 4 5 6 8 4 7 3
程序出来是46,正确答案是49,模拟一番发现居然变道了两次,但是程序里明明写着当转弯次数>k时直接continue不可能会转两次的啊,最后发现其实是dis数组的缘故,因为平时习惯了用一维的dis数组来表示单源最短距离,其实错误的答案并不是变道两次造成的,而是路径中某一个点本身是从上面的点扩展而来,不需经过变道即可获得最短路径,但是却被后面更新的路错误地拼接到了拓展队列里,简单地说这一条距离为46的路径是不存在的,是由两条路径错误地拼接而成大概如下图(画的比较抽象,只需要感性的认识一下……)
其中上面红色的终点是被拓展了,但是你下面的蓝色又拓展到对称点的时候又反过来利用了红色的信息,而且此时蓝色状态k=0,错误地进行了拓展。
那么如何解决呢?我是增加了一维dis[n][k]表示第n个点变道k次的最短距离,这样的好处就是状态更新的时候不会错误地拿本身不衔接的状态进行更新。然后就过了。
再说一下DP解法吧,写出来其实是一个比较简单的递推DP,递推方程:
\begin{cases}dp[n][k][0]=min(dp[n-1][k][0]+a[i],dp[n-1][k-1][1]+b[i]), \\dp[n][k][1]=min(dp[n-1][k][1]+b[i],dp[n-1][k-1][0]+a[i])
, \end{cases}
DP代码:
- #include <stdio.h>
- #include <bits/stdc++.h>
- using namespace std;
- #define INF 0x3f3f3f3f
- #define CLR(arr,val) memset(arr,val,sizeof(arr))
- #define LC(x) (x<<1)
- #define RC(x) ((x<<1)+1)
- #define MID(x,y) ((x+y)>>1)
- typedef pair<int,int> pii;
- typedef long long LL;
- const double PI=acos(-1.0);
- const int N=10010;
- LL a[N],b[N];
- LL dp[N][12][2];
- int main(void)
- {
- int tcase,i,j,n,k;
- scanf("%d",&tcase);
- while (tcase--)
- {
- CLR(dp,0);
- scanf("%d%d",&n,&k);
- for (i=1; i<=n; ++i)
- scanf("%lld",&a[i]);
- for (i=1; i<=n; ++i)
- scanf("%lld",&b[i]);
- dp[1][0][0]=a[1];
- dp[1][0][1]=b[1];
- for (i=1; i<=n; ++i)
- {
- for (j=0; j<=k; ++j)
- {
- if(j==0)
- {
- dp[i][0][0]=dp[i-1][0][0]+a[i];
- dp[i][0][1]=dp[i-1][0][1]+b[i];
- }
- else
- {
- dp[i][j][0]=min<LL>(dp[i-1][j][0]+a[i],dp[i-1][j-1][1]+a[i]);
- dp[i][j][1]=min<LL>(dp[i-1][j][1]+b[i],dp[i-1][j-1][0]+b[i]);
- }
- }
- }
- LL ans=1e20;
- for (i=0; i<=k; ++i)
- ans=min<LL>(ans,min<LL>(dp[n][i][0],dp[n][i][1]));
- printf("%lld\n",ans);
- }
- return 0;
- }
最短路代码:(cin取消同步之后居然比scanf快……服了)
- #include <stdio.h>
- #include <bits/stdc++.h>
- using namespace std;
- #define INF 0x3f3f3f3f
- #define CLR(arr,val) memset(arr,val,sizeof(arr))
- #define LC(x) (x<<1)
- #define RC(x) ((x<<1)+1)
- #define MID(x,y) ((x+y)>>1)
- typedef pair<int,int> pii;
- typedef long long LL;
- const double PI=acos(-1.0);
- const int N=10100;
- struct edge
- {
- int to,nxt;
- LL w;
- int flag;
- };
- edge E[N<<2];
- int head[N<<1],tot;
- LL a[N],b[N],d[N<<1][11];
- int n,k;
- bool vis[N<<1][11];
- void init()
- {
- CLR(head,-1);
- tot=0;
- CLR(d,INF);
- CLR(vis,false);
- }
- inline void add(int s,int t,LL d,int f)
- {
- E[tot].to=t;
- E[tot].flag=f;
- E[tot].w=d;
- E[tot].nxt=head[s];
- head[s]=tot++;
- }
- void spfa(int s)
- {
- vis[s][0]=1;
- d[s][0]=0LL;
- queue<pii>Q;
- Q.push(pii(s,0));
- while (!Q.empty())
- {
- int now=Q.front().first;
- int nk=Q.front().second;
- Q.pop();
- vis[now][nk]=0;
- for (int i=head[now]; ~i; i=E[i].nxt)
- {
- int v=E[i].to;
- int vk=nk+E[i].flag;
- if(vk>k)
- continue;
- if(d[v][vk]>d[now][nk]+E[i].w)
- {
- d[v][vk]=d[now][nk]+E[i].w;
- if(!vis[v][vk])
- {
- vis[v][vk]=1;
- Q.push(pii(v,vk));
- }
- }
- }
- }
- }
- int main(void)
- {
- ios::sync_with_stdio(false);
- cin.tie(0);
- int tcase,i;
- cin>>tcase;
- while (tcase--)
- {
- init();
- cin>>n>>k;
- for (i=1; i<=n; ++i)
- cin>>a[i];
- for (i=1; i<=n; ++i)
- cin>>b[i];
- int S=0;
- for (i=1; i<=n; ++i)
- add(i,i+1,a[i],0);
- for (i=1; i<=n; ++i)
- add(n+i+1,n+2+i,b[i],0);
- for (i=1; i<=n+1; ++i)
- {
- add(i,n+i+1,0LL,1);
- add(n+i+1,i,0LL,1);
- }
- add(S,1,0LL,0);
- add(S,n+2,0LL,0);
- spfa(0);
- LL minm=d[(N<<1)-1][0];
- for (i=0; i<=k; ++i)
- minm=min(minm,d[n+1][i]);
- for (i=0; i<=k; ++i)
- minm=min(minm,d[2*n+2][i]);
- cout<<minm<<endl;
- }
- return 0;
- }
FJNU 1196 汪老司机(DP or 建图+最短路)的更多相关文章
- luogu P2304 [NOI2015]小园丁与老司机 dp 上下界网络流
LINK:小园丁与老司机 苦心人 天不负 卧薪尝胆 三千越甲可吞吴 AC的刹那 真的是泪目啊 很久以前就写了 当时记得特别清楚 写到肚子疼.. 调到胳膊疼.. ex到根不不想看的程度. 当时wa了 一 ...
- 【BZOJ4200】[Noi2015]小园丁与老司机 DP+最小流
[BZOJ2839][Noi2015]小园丁与老司机 Description 小园丁 Mr. S 负责看管一片田野,田野可以看作一个二维平面.田野上有 nn 棵许愿树,编号 1,2,3,…,n1,2, ...
- uva10067 Playing with Wheels 【建图+最短路】
题目:option=com_onlinejudge&Itemid=8&page=show_problem&problem=1008">uva10067 Play ...
- 【建图+最短路】Bzoj1001 狼抓兔子
Description 现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的,而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个 ...
- BZOJ 4289: PA2012 Tax 差分建图 最短路
https://www.lydsy.com/JudgeOnline/problem.php?id=4289 https://www.cnblogs.com/clrs97/p/5046933.html ...
- CodeForces 786B Legacy(线段树优化建图+最短路)
[题目链接] http://codeforces.com/problemset/problem/786/B [题目大意] 给出一些星球,现在有一些传送枪,可以从一个星球到另一个星球, 从一个星球到另一 ...
- HDU 4725 The Shortest Path in Nya Graph( 建图 + 最短路 )
主要是建图,建好图之后跑一边dijkstra即可. 一共3N个点,1~N是原图中的点1~N,然后把每层x拆成两个点(N+x)[用于连指向x层的边]和(N+N+x)[用于连从x层指出的边]. 相邻层节点 ...
- 【转】Codeforces Round #406 (Div. 1) B. Legacy 线段树建图&&最短路
B. Legacy 题目连接: http://codeforces.com/contest/786/problem/B Description Rick and his co-workers have ...
- G. 神圣的 F2 连接着我们 线段树优化建图+最短路
这个题目和之前写的一个线段树优化建图是一样的. B - Legacy CodeForces - 787D 线段树优化建图+dij最短路 基本套路 之前这个题目可以相当于一个模板,直接套用就可以了. 不 ...
随机推荐
- extractor
package scrollable.excel.reader; import java.io.IOException; import java.io.InputStream; import java ...
- log4net部分配置说明
第一步: 添加并应用Log4net.dll.然后在Web.config文件中添加下面的配置局 <configSections> <section name="log ...
- windows系统和ubuntu虚拟机之间文件共享——samba
参考:http://www.cnblogs.com/phinecos/archive/2009/06/06/1497717.html 一. samba的安装: sudo apt-get insall ...
- 进度条ProgressDialog
1.效果图 public void click(View view) { final ProgressDialog pdDialog = new ProgressDialog(this); //设置标 ...
- C#中将DataTable转成List
学习MVC的时候,使用List<T>来存储数据给前台,但是从数据库中直接读取得到的是DataTable,虽然可以直接循环DataTable来得到list,但是如果每个实体类都通过这样的得到 ...
- .NET 获取客户端的操作系统版本、浏览器版本和IP地址
我们在使用.NET做网站的时候,很多情况下需要需要知道客户端的操作系统版本和浏览器版本,怎样获取客户端的操作系统和浏览器版本呢?我们可以通过分析UserAgent来获取. .NET 获取客户端的操作系 ...
- Python requests模拟登录
Python requests模拟登录 #!/usr/bin/env python # encoding: UTF-8 import json import requests # 跟urllib,ur ...
- 【Java EE 学习 28 上】【oracle学习第二天】【子查询】【集合运算】【几种数据库对象】
一.子查询 1.为什么要使用子查询:问题不能一步求解或者一个查询不能通过一步查询得到. 2.分类:单行子查询和多行子查询. 3.子查询的本质:一个查询中包含了另外一个或者多个查询. 4.使用子查询的规 ...
- Knockout.js随手记(5)
以列表方式呈现数据 处理以数组形式储存的多条数据,要先认识foreach.在ViewModel定义一个JavaScript Array或是ko.observableArray() (observab ...
- CozyRSS开发记录2-酷炫的皮肤库
CozyRSS开发记录2-酷炫的皮肤库 1.MaterialDesignToolkit 最开始微软推出Metro设计风格的时候,有人喜欢有人喷.紧接着,Ios也开始做扁平化的UI,这时候,扁平化已成为 ...