您的位置:首页 > 大数据 > 人工智能

hdu 2291 Five in a Row, Again 状态压缩搜索

2015-09-01 15:41 274 查看
题目地址

题目描述:(借鉴别人的

给两个n*n的矩阵,第一个代表一个人战胜一个人可以得到的经验值,第二个代表一个人战胜另一个人可以得到的分数,然后n个数,代表n个人的初始经验值,只有经验值大于对手才可以取胜,问第一个人最后取得的最大分数。

感悟:一开始根本看不懂这个题,最后看了多个博客,读了代码才知道其实就是暴力搜索,只是用了状态压缩(要不然直接模拟代码较长),感觉根本没什么技巧。
        还有我突然发现,原来题目的输入的两个矩阵,除了第一行最后都是没用的数据。   还有居然发现 【if(a<c+b) a=c+b;】  比 【d=c+b; if(a<d)a=d;】耗时,测试时好像是多用15MS。只是说一下也不用在意。
        此题本质就是用状态压缩,用一个数字表示 leader 与其余几人的对战情况(我的注释都描述成战斗了) , 所有状态以及每个状态最后一次该战胜谁都遍历求解,以达到最好的结果(其实这就是dp的状态转移吧)。 还有关于经验的计算一开始可以打表直接查询,但即使每次重新求一遍经验也能过,所以没有另外处理。
程序的注释写了不少,也算是第一次使用状态压缩吧!

#include<string.h>
#include<stdio.h>
#define MAXNUM 15
int dp[1<<MAXNUM];
int e[MAXNUM],w[MAXNUM],s[MAXNUM]; //通过题目发现,矩阵只有第一行有用,其余作废
int main(){
int t,n,i,j,k;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(i=0;i<n;i++)scanf("%d",&e[i]); for(i=n;i<n*n;i++)scanf("%d",&j);
for(i=0;i<n;i++)scanf("%d",&w[i]); for(i=n;i<n*n;i++)scanf("%d",&j);
for(i=0;i<n;i++)scanf("%d",&s[i]);
memset(dp,0,sizeof(dp));
//将DP用于直接计算的方式, 有的是将DP用于DFS的剪枝
int all_state=1<<(n-1); //获得了所有组合的状态总数 ,不包括第一人
for(i=0;i<all_state;i++){ //求i状态的dp值(遍历所有状态,包含了人数从小到大的过程*** )
for(j=0;j<n-1;j++){ //leader 不算
if( i&(1<<j) ){ //这个状态下,新来这个选手参与和 leader 的比较
int tmp_i=i^(1<<j); //相同为 0 ,即考虑没和 j 比较前的状态
int id=0;// 其实就是能打败的人的编号
int tmp=s[id];
//下面这部分其实可以利用存储优化的
for(id=1;id<n-1;id++){
if( 1&( tmp_i>>(id-1) )){ //与第一位判断就要位移 0
tmp+=e[id];//说明之前打过就攒下了经验
}
}
if(tmp>s[ j+1 ]){ //能打过
//只会发生在同层循环内,也就是打斗的先后循序不一样
tmp= dp[tmp_i] + w[j+1]; //就这里一个优化,能节省 15MS? 我试了半天
if( dp[i]< tmp ) dp[i]=tmp;
}
}
}
}
printf("%d\n",dp[ all_state-1 ]); // 最后一个就是打完所有的最好的结果
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  状态压缩