蜘蛛牌

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3761    Accepted Submission(s):
1606

Problem Description
蜘蛛牌是windows
xp操作系统自带的一款纸牌游戏,游戏规则是这样的:只能将牌拖到比她大一的牌上面(A最小,K最大),如果拖动的牌上有按顺序排好的牌时,那么这些牌也跟着一起移动,游戏的目的是将所有的牌按同一花色从小到大排好,为了简单起见,我们的游戏只有同一花色的10张牌,从A到10,且随机的在一行上展开,编号从1到10,把第i号上的牌移到第j号牌上,移动距离为abs(i-j),现在你要做的是求出完成游戏的最小移动距离。
 
Input
第一个输入数据是T,表示数据的组数。
每组数据有一行,10个输入数据,数据的范围是[1,10],分别表示A到10,我们保证每组数据都是合法的。
 
Output
对应每组数据输出最小移动距离。
 
Sample Input
1
1 2 3 4 5 6 7 8 9 10
 
Sample Output
9
 
Author
xhd
 
Source

很久之前...开学初吧困扰自己的一道破题,当时竟然连爆搜都没想到。

这个牌任意移动,所以每次的出发点并不固定,当时一直按照固定的方法来做自然WA了= =,今天写刚开始是个无剪纸爆搜2000+ms。。。。

后来发现剪枝:当总步数大于当前最小步数时,直接return,总算卡进1000ms内了,300+,看榜单都是0ms。。。原来还能用区间dp求解,而且我发现自己把这个搜索想的复杂了。

仔细想想,假设从一个位置移动到另一个位置算一次移动的话,无论怎么操作,最终(不做无意义的移动时)都要移动九次即可,只是总步数不同而已,一开始并没有想到这个!

原先搜索代码:

#include<bits/stdc++.h>
using namespace std;
struct Pock                                  //结构体保存当前位置最小和最大牌面值
{
int up,down;
}a[15];
int s;
int debug=10;
bool pd()
{
int book=0,i;
for(i=1;i<=debug;++i)
if(a[i].up==0&&a[i].down==0) ++book;
return (book==debug-1?1:0);
}
void dfs(int sumn)
{
if(sumn>=s) return;                              //剪枝1,步数大于最小时直接return
if(pd()){
if(sumn<s) s=sumn;
return;
}

for(int i=1;i<=debug;++i){
if(a[i].up!=0&&a[i].down!=0){
for(int j=1;j<=debug;++j){
if(i==j) continue;
if(a[i].up+1==a[j].down){
int tup=a[i].up;
int tdown=a[i].down;
int jdown=a[j].down;
a[i].up=a[i].down=0;
a[j].down=tdown;

dfs(sumn+abs(i-j));

a[i].up=tup;
a[i].down=tdown;
a[j].down=jdown;

break;                                         //剪枝2,比i位置up值大一的位置只会出现一个,所以搜索完直接break;
}
}
}
}
}
int main()
{
int n,t,i,j,c;
scanf("%d",&t);
while(t--){s=1e9;
for(i=1;i<=debug;++i){
scanf("%d",&c);
a[i].up=c;
a[i].down=c;
}
dfs(0);
printf("%d\n",s);
}
return 0;
}

优化后的剪枝:

#include<bits/stdc++.h>
using namespace std;
int a[15],s;
bool vis[15];
void dfs(int cur,int sumn)
{
if(sumn>=s) return;
if(cur==10){
s=sumn;
return;
}
for(int i=1;i<=10;++i){
if(!vis[i]){
vis[i]=1;
for(int j=i+1;j<=10;++j){
if(!vis[j]){
dfs(cur+1,sumn+abs(a[i]-a[j]));
break;
}
}
vis[i]=0;
}
}
}
int main()
{
int i,j,t;
cin>>t;
while(t--){s=1e10,memset(vis,0,sizeof(vis));
for(i=1;i<=10;++i) {cin>>j;a[j]=i;}
dfs(1,0);
cout<<s<<endl;
}
return 0;
}

优化原理:

a[i]即面值为i的牌所在位置,之所以这样写是为了方便搜索,

一:面值为m的牌的位置只可能出现在面值>=m的位置上,因为只能把小牌移动到大牌上!

二:移动次数超过九次说明已经移动完毕!

这个写法简直不能再帅了!!!

DP做法:

我们在合牌的过程中总会把牌分成了最后的两堆,然后将这两堆合并后合并完成!

那么有多少种这样的可能呢?,显然:1-->k,k+1-->10(1<=k<10),不妨用一个二维数组记录这个操作,

dp[i][j]表示将牌面排成i->i+1->i+2......j需要的最少移动距离,那么显然我们需要的答案是dp[1][10];

由此得出状态转移方程: dp[i][j]=MIN(dp[i][k]+dp[k+1][j]+abs(a[k]-a[j]) | (i<=k<j) )

假设i,j表示面值,

显然想求得跨度为n=abs(i-j)的dp[i][j]的话需要跨度为1-->n-1的dp值才可继续递推下去,因此我们应该从跨度由低到高递推即可:

#include<bits/stdc++.h>
using namespace std;
int dp[11][11],a[11];
int main()
{
int t,i,j,k,e;
cin>>t;
while(t--){memset(dp,0,sizeof(dp));
for(i=1;i<=10;++i) cin>>e,a[e]=i;
for(k=1;k<10;++k)                             //枚举跨度
for(i=1;i+k<=10;++i){e=i+k;int M=999999999;
for(int temp=i;temp<e;++temp)
M=min(M,dp[i][temp]+dp[temp+1][e]+abs(a[temp]-a[e]));                //找出最优的分割点
dp[i][e]=M;
}
cout<<dp[1][10]<<endl;
}
return 0;
}

hdu1584的更多相关文章

  1. HDU-1584 蜘蛛牌(dfs)

    可以多看看. 蜘蛛牌 Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Tota ...

  2. HDU1584:蜘蛛牌(DFS)

    Problem Description 蜘蛛牌是windows xp操作系统自带的一款纸牌游戏,游戏规则是这样的:只能将牌拖到比她大一的牌上面(A最小,K最大),如果拖动的牌上有按顺序排好的牌时,那么 ...

  3. hdu1584 A strange lift (电梯最短路径问题)

    A strange lift Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) T ...

  4. HDU1584(蜘蛛牌)

    蜘蛛牌 Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submis ...

  5. ACM学习历程—HDU1584 蜘蛛牌(动态规划 && 状态压缩 || 区间DP)

    Description 蜘蛛牌是windows xp操作系统自带的一款纸牌游戏,游戏规则是这样的:只能将牌拖到比她大一的牌上面(A最小,K最大),如果拖动的牌上有按顺序排好的牌时,那么这些牌也跟着一起 ...

  6. hdu1584(状态压缩DP)

    蜘蛛牌 Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submis ...

随机推荐

  1. fastDFS errcode:9 path:Bad file descriptor errcode:22 path:Invalid argument

    fastDFS errcode:9 path:Bad file descriptor errcode:22 path:Invalid argument <error>status:4 er ...

  2. QEvent postEvent/sendEvent

    可以自訂事件類型,最簡單的方式,是透過QEvent::Type指定事件類型的常數值,在建構QCustomEvent時作為建構引數並透過postEvent()傳送事件,例如: const QEvent: ...

  3. 手撕vue-cli配置——webpack.dev.conf.js篇

    const utils = require('./utils') const webpack = require('webpack') const config = require('../confi ...

  4. OpenCV中HSV颜色模型及颜色分量范围

    HSV颜色模型 HSV(Hue, Saturation, Value)是根据颜色的直观特性由A. R. Smith在1978年创建的一种颜色空间, 也称六角锥体模型(Hexcone Model)..这 ...

  5. c++中的字符集与中文

    就非西欧字符而言,比如中国以及港澳台,在任何编程语言的开发中都不得不考虑字符集及其表示.在c++中,对于超过1个字节的字符,有两种方式可以表示: 1.多字节表示法:通常用于存储(空间效率考虑). 2. ...

  6. 20145318《网络对抗》Web应用

    20145318<网络对抗>Web应用 基础问题回答 (1)什么是表单 在网页中负责信息采集,在网页中用户输入信息,通过表单能够提交到后台进行相应的处理 (2)浏览器可以解析运行什么语言 ...

  7. Educational Codeforces Round 21 Problem E(Codeforces 808E) - 动态规划 - 贪心

    After several latest reforms many tourists are planning to visit Berland, and Berland people underst ...

  8. Java序列化流-ObjectOutputStream、ObjectInputStream

    Java对象流的基本概念: 实例代码: 实体类User: import java.io.Serializable; /** * @author zsh * @company wlgzs * @crea ...

  9. idata,xdata,pdata,code

    data       --->   可寻址片内ram bdata     --->  可位寻址的片内ram idata      --->   可寻址片内ram,允许访问全部内部ra ...

  10. POJ 1236 Network of Schools(tarjan)题解

    题意:一个有向图.第一问:最少给几个点信息能让所有点都收到信息.第二问:最少加几个边能实现在任意点放信息就能传遍所有点 思路:把所有强连通分量缩成一点,然后判断各个点的入度和出度 tarjan算法:问 ...