标签:允许 dac 情况 abs air fps 代码实现 rom dfa
题目描述
开启了升降梯的动力之后,探险队员们进入了升降梯运行的那条竖直的隧道,映入眼帘 的是一条直通塔顶的轨道、一辆停在轨道底部的电梯、和电梯内一杆控制电梯升降的巨大手 柄。 Nescafe 之塔一共有 N 层,升降梯在每层都有一个停靠点。手柄有 M 个控制槽,第 i 个控制槽旁边标着一个数 Ci,满足 C1<??0,表示手柄扳动到该槽 时,电梯将上升 Ci 层;如果 Ci<0,表示手柄扳动到该槽时,电梯将下降-Ci 层;并且一定 存在一个 Ci=0,手柄最初就位于此槽中。注意升降梯只能在 1~N 层间移动,因此扳动到使 升降梯移动到 1 层以下、N 层以上的控制槽是不允许的。 电梯每移动一层,需要花费 2 秒钟时间,而手柄从一个控制槽扳到相邻的槽,需要花费 1 秒钟时间。探险队员现在在 1 层,并且想尽快到达 N 层,他们想知道从 1 层到 N 层至少 需要多长时间? <??
<??输入格式 第一行两个正整数 N、M。 第二行 M 个整数 C1、C2??CM。 <??
<??输出格式 输出一个整数表示答案,即至少需要多长时间。若不可能到达输出-1。 <??
<??样例输入 6 3 -1 0 2<??
<?? 样例输出 19 <??
<??样例说明 手柄从第二个槽扳到第三个槽(0 扳到 2),用时 1 秒,电梯上升到 3 层,用时 4 秒。 手柄在第三个槽不动,电梯再上升到 5 层,用时 4 秒。 手柄扳动到第一个槽(2 扳到-1),用时 2 秒,电梯下降到 4 层,用时 2 秒。 手柄扳动到第三个槽(-1 扳倒 2),用时 2 秒,电梯上升到 6 层,用时 4 秒。 总用时为(1+4)+4+(2+2)+(2+4)=19 秒。<??
<?? 数据范围与约定 对于 30% 的数据,满足 1≤N≤10,2<=M<=5。 对于 100% 的数据,满足 1≤N≤1000,2<=M<=20,-N<C1<C2<…<CM<N.<??
题目描述
探险队员们顺利乘坐升降梯来到了塔顶。塔顶有若干房间,房间之间连有通道。如果把 房间看做节点,通道看做边的话,整个塔顶呈现一个有根树结构,并且每个房间的墙壁都涂 有若干种颜色的一种。 现在探险队员们在树根处,他们打算进一步了解塔顶的结构,为此,他们使用了一种特 殊设计的机器人。这种机器人会从队员身边,也就是树根出发,之后对塔顶进行深度优先遍 历。机器人每进入一个房间(无论是第一次进入还是返回),都会记录这个房间的颜色。最 后,机器人会回到树根。 显然,机器人会访问每个房间至少一次,并且穿越每条通道恰好两次(两个方向各一次), 然后,机器人会得到一个颜色序列。但是,探险队员发现这个颜色序列并不能唯一确定塔顶 的结构。现在他们想请你帮助他们计算,对于一个给定的颜色序列,有多少种可能的结构会 得到这个序列。由于结果可能会非常大,你只需要输出答案对 10^9 取模之后的值。 输入格式 输入文件包含一行,含有一个字符串,表示机器人得到的颜色序列。
输出格式 输出一个整数表示答案。
样例输入 ABABABA
样例输出 5
样例说明 有如下 5 种方案。注意子树之间是有序的,所以(3)和(4)是两种不同的方案。
数据范围与约定 对于 24% 的数据,字符串的长度不超过 20。 对于 100% 的数据,字符串的长度不超过 300。
T3礼物运送
题目描述
机器人刚刚探查归来,探险队员们突然发现自己的脚下出现了一朵朵白云,把他们托向 了空中。一阵飘飘然的感觉过后,队员们发现自己被传送到了一座空中花园。 “远道而来的客人,我们是守护 Nescafe 之塔的精灵。如果你们想拜访护法和圣主的话, 就要由我们引路。因此,你们是不是该给我们一点礼物呢 T_T?” 队员们往远处一看,发现花园中有 N 个木箱,M 条柔软的羊毛小路,每条小路的两个 端点都是木箱,并且通过它需要 ti 的时间。队员们需要往每个木箱中放一份礼物,不过由 于精灵们不想让花园被过多地踩踏,因此运送礼物的任务最多只能由两位探险队员完成。 两位探险队员同时从 1 号木箱出发,可以在任意木箱处结束运送。运送完毕时,每只木 箱应该被两位队员中至少一人访问过。运送任务所用的时间是两人中较慢的那个人结束运送 任务的时间。请问这个时间最快是多少呢?
输入格式 第一行两个正整数 N、M。 接下来 M 行每行三个整数 xi、yi、ti,表示 xi 和 yi 之间有一条用时为 ti 的小路,小路 是双向的。
输出格式 输出所需的最短时间。
样例输入
6 6
1 2
10 2
3 10
3 4
5 4
5 10
5 6
20 2
5 10
样例输出
40
数据范围与约定 对于 50%的数据,1<=N<=9。 对于 100%的数据,1<=N<=18,1<=ti<=1000,1<=xi,yi<=N,两个木箱之间最多只有一 条小路,不会有自己到自己的小路,保证所有木箱是连通的。
昨天寝室里开夜车写作业的太多,灯亮如白昼。没睡好,所以今天考试灵魂简直在游荡,灌了大半杯咖啡后才好一些,最奇妙的是,我没有做出简单题T1,却把比较有思维量的T2想出来了。。然后就写挂了,处于爆零边缘。。解就一起写了,难免有些水,建立在大家都认真思考过的基础上吧。
T1:
可能是我阅历不够,我首先想到的是dp(不再赘述),但是发现dp有后效性,而且记忆化会死循环(因为有负数),我那时就突然想到了建图。然后我们考虑对层数i建图,但是根本不行,你不能直接在节点i上加边,因为在你的控制槽位置不确定的情况下,你无法确定边的大小。所以就可以将一个二元组看成一个点。即(i,k),考虑非常显然的(i,k)到(i+a[j],j)的边为abs(k-j)+2*abs(a[j]);有这样一个图之后,你从起点(1,k0)到终点(n,j),j=1~m,a[k0]=0的;为什么能,你可以把最短路看成更广的具后效性的dp,用你的建图直觉和dp直觉去理解。
到这里还远远不够,这个题比较烦的应该是代码实现,(如果你是初次遇到这个题的话),仔细看。注意下面几点:
1.如何将二元组建在一起 2.有没有必要建图 (这里只专门用数据来存)
1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 #include <cmath> 5 #include <algorithm> 6 #include <queue> 7 #define N 1010 8 #define M 210 9 #define inf 0x3f3f3f3f 10 #define Run(i,l,r) for(int i=l;i<=r;i++) 11 #define Don(i,l,r) for(int i=l;i>=r;i--) 12 using namespace std; 13 struct node{int i,j; bool operator < (const node& a)const{return i<a.i;} }; 14 typedef pair<int,node>pii; 15 priority_queue<pii,vector<pii>,greater<pii> >q; 16 int vis[N][M],dis[N][M]; 17 int n,m,a[M]; 18 int main() 19 { freopen("updown.in","r",stdin); 20 freopen("updown.out","w",stdout); 21 cin>>n>>m; 22 int sj; 23 Run(i,1,m){ 24 cin>>a[i]; 25 if (!a[i]) sj=i; 26 } 27 memset(dis,0x3f,sizeof(dis)); 28 dis[1][sj]=0; 29 q.push(make_pair(dis[1][sj],(node){1,sj})); 30 vis[1][sj]=1; 31 while (!q.empty()) 32 {node u=q.top().second; 33 q.pop(); vis[u.i][u.j]=0; 34 for(int j=1;j<=m;j++) 35 {node v=(node){u.i+a[j],j}; 36 if (v.i<1||v.i>n) continue; 37 if (dis[v.i][v.j]>dis[u.i][u.j]+abs(j-u.j)+2*abs(a[j])) 38 {dis[v.i][v.j]=dis[u.i][u.j]+abs(j-u.j)+2*abs(a[j]); 39 if (!vis[v.i][v.j]) {q.push(make_pair(dis[v.i][v.j],v)); 40 vis[v.i][v.j]=1; 41 }} 42 } 43 44 } 45 int ans=0x3f3f3f3f; 46 Run(i,1,m) ans=min(ans,dis[n][i]); 47 cout<<((ans==inf)?-1:ans)<<endl; 48 return 0; 49 }
T2:
这个题就是我唯一写了但是写挂了的QAQ,它其实是个区间dp。我开始也从一般的dp去考虑:
不分析细节,那么就有这样一件事情,在同一个串(例ABABABA)里狡猾的A颜色(除第一个外和最后一个),有可能是dfs回来的根节点,也有可能是
在是[l,r]中s[l]==s[r]时,考虑s为AS1AS2A…….A的形式Sn表示一个字符串集,即
如果我们要专门去讨论s1到sn的话,还要生成子集,代码复杂性提高了不说,时间也过不了。而我们本身写的就是dp,所以可以利用这个优势,在划分[l,r]的手段上变化:具体就是我们不关心s2到sn,只枚举s1,然后将AS2AS2AS3..SNA原样(就变成了一个更小的子问题)dp而将s1dp即S1,(s1无头尾的A),至于l还是从r枚举s1,就是随便了。写出转移方程:
dp[l,r]=sigma(dp[l+1,k]*dp[k,r]) (s[l]==s[r]&&s[l]==s[k] ).
1 #include <cstdio> 2 #include <iostream> 3 #include <algorithm> 4 #include <cstring> 5 #define N 310 6 #define inf 0x3f3f3f3f 7 #define Mod 1000000001 8 #define Run(i,l,r) for(int i=l;i<=r;i++) 9 #define Don(i,l,r) for(int i=l;i>=r;i--) 10 using namespace std; 11 char s[N]; 12 int f[N][N]; 13 int main() 14 { 15 freopen("probe.in","r",stdin); 16 freopen("probe.out","w",stdout); 17 cin>>s; 18 int len=strlen(s)-1; 19 Run(i,0,len) f[i][1]=1; 20 21 22 Run(l,3,len+1) 23 for(int i=0;i+l-1<=len;i++) 24 {int j=i+l-1; 25 if (s[i]==s[j]){ 26 Don(k,j,i+2) 27 if (s[i]==s[k]) f[i][l]=(f[i][l]+1ll*f[i+1][k-i-1]*f[k][j-k+1]%Mod)%Mod; 28 } 29 } 30 cout<<f[0][len+1]<<endl; 31 return 0; 32 }
T3
先看数据范围可以猜出是状压dp,然而他们是两个人一起走,而又没说不能走相同的地方之类的,所以我们不妨将此题看为一个人走。如果不这样,设计状态是就要三维,分别为1号人最后走到的地方i,2号人最后走到的地方j,和此时两人一共走过的集合s
(二进制状压),你悄悄算算就会发现一件很奇妙的事情:MLE。所以我们只能考虑记录一个i,s所以得到的应该是对于这个图的每一种遍历过的点集s,走到的末位置为i的情况下的最少步数。考虑两个人无论谁走都是一样的,那么我们想要得到答案就应该是min{max(f[s|1,i],f[((1<<n)-1-s)|1,j])} (ij∈V);(之所以要|1是因为1是出发点,其他点可以取反,但1不能)
所以是这样的吗?如果你照着这个思路用普通的状压dp扩展你会发现你连样例都过不了。因为样例中12还共同走了一段而这一段是必须的。如何把这一段加进去呢——其实,跑最短路将连通图的每两个点的最短距离算出来即可,因为在运用最短路扩展时,计算dis[][]数组会加进一些必要经过的点并且这些点是最优的,所以现在我们完善状态:一定会经过s中点,但经过的点不一定是S(子集关系)应为有可能多经过其他点,而更优。那所以到这里状态转移方程才是正确的。建议用floyd求多源点最短路。
1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 #include <queue> 5 #include <algorithm> 6 #include <vector> 7 #include <cmath> 8 #include <ctime> 9 #define N 20 10 #define inf 0x3f3f3f3f 11 #define Run(i,l,r) for(int i=l;i<=r;i++) 12 #define Don(i,l,r) for(int i=l;i>=r;i--) 13 using namespace std; 14 int n,m,dis[N][N]; 15 int f[1<<N][N]; 16 int main() 17 { 18 freopen("transport.in","r",stdin); 19 freopen("transport.out","w",stdout); 20 cin>>n>>m; 21 memset(dis,0x3f,sizeof(dis)); 22 Run(i,1,m) 23 {int u,v,w; 24 cin>>u>>v>>w; 25 dis[u][v]=dis[v][u]=w; 26 } 27 Run(i,1,n) dis[i][i]=0; 28 Run(k,1,n)Run(i,1,n)Run(j,1,n) if(dis[i][k]+dis[k][j]<dis[i][j]) dis[i][j]=dis[i][k]+dis[k][j]; 29 memset(f,0x3f,sizeof(f)); 30 31 f[1][1]=0; 32 Run(i,1,(1<<n)-1) Run(j,1,n) 33 if ((1<<j-1)&i) 34 Run(k,1,n)if (((1<<k-1)&(i))&&f[i][j]>f[i-(1<<j-1)][k]+dis[k][j]&&i!=j) f[i][j]=f[i-(1<<j-1)][k]+dis[k][j]; 35 36 Run(i,1,(1<<n)-1) 37 Run(j,1,n) 38 f[i][0]=min(f[i][0],f[i][j]); 39 int ans=inf; 40 Run(i,1,(1<<n)-1) 41 {ans=min(ans,max(f[i|1][0],f[((1<<n)-1-i)|1][0])); 42 } 43 Run(i,1,(1<<n)-1) cout<<f[i][0]<<" "; 44 cout<<endl; 45 cout<<ans<<endl; 46 return 0; 47 }
总结:
1.区间DP的l要放在最外边;
3.注意spfa可以用priotity优化,然后加入队列的条件是v不在队列里且被更新了;
判环的方法就是更新次数超过n-1次;
3.flyod的k应该在最外面(先记着,有感性的理解,说不定那天有灵感就相出来了)
4.写dp时,务必注意初值!!!和方程;请动脑子打程序,不然会花去十倍的时间调试;这也是你为什么比其他人落后的原因,常规一样,初中也一样,不改必误你一生;
标签:允许 dac 情况 abs air fps 代码实现 rom dfa
原文地址:http://www.cnblogs.com/AUSTIN-tkys/p/7618469.html