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;
}
题目描述:(借鉴别人的)
给两个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;
}
相关文章推荐
- 2014辽宁省赛 Picking Cabbage 状压dp
- 状态压缩DP joboj1430 shortest path 和 codeforces Problem 21 D Traveling Graph
- 状态压缩DP poj—1185 炮兵阵地 和 cf 111 Problem C Petya and Spiders (经典)
- 动态规划状态压缩题解
- LA 6450 Social Advertising
- POJ2411(状态压缩DP)
- HDU 5135 Little Zu Chongzhi's Triangles(状态压缩)
- UVa 12317 (状态压缩DP)
- HDU 3362 (状态压缩DP)
- poj 3254 Corn Fields
- POJ 1185 炮兵阵地 经典状态压缩DP
- POJ 3311 Hie with the Pie 状态压缩DP
- HDU 3001 Travelling 状态压缩dp+3进制
- zoj 3471状态压缩DP
- POJ 2411Mondriaan's Dream
- HDU 4628 状态压缩
- HDU 3006
- Codeforces Round #235 (Div. 2) D. Roman and Numbers
- 状压dp小结
- hdu1429推箱子