hdu6407(恶心状压dp)

本文介绍了一种复杂的动态规划算法,用于解决一种新型气球爆炸游戏的最优策略问题。通过转换行列和使用三进制状态表示,将问题转化为求解不同状态下气球爆炸次数的最优解。算法复杂度为O(n*m*3^m),实现中涉及高级数据结构和算法技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这个题可以说是十分十分恶心的题了。。

状态还是很容易想出来的,设d[i][S]为处理到i行时各列的状态,其中0表示该列没有气球,1表示该列已经被炸过,2表示该列有气球还没被炸掉,然后发现行比列小所以把行列转置一下就能降低复杂度。。。

然后分该行有没有选择气球炸掉和选哪个炸掉去转移就可以了。。

复杂度是O(n*m*3^m)。。emmmm为什么没有k。。因为S就表明了炸了几次(列),已经包含了k。。

然后实现才是最恶心的。。。

一方面是三进制比较难写。。想着用4进制表示能用位运算加速。。结果发现dp滚动数组的申请已经就把内存刚好用光了,必须写三进制(被出题人安排得明明白白

另一方面是答案会爆longlong,要写小高精。。(取个模会死嘛qaq

然后是滚动数组不能赋值,必须边转移边清空,即用01滚动数组。。以后写滚动都用这个了。。

总之写得很吐血,跑起来也很慢。。这1e10的复杂度算出来估计窝当场都不敢写。。

 

 

/**
 *          ┏┓    ┏┓
 *          ┏┛┗━━━━━━━┛┗━━━┓
 *          ┃       ┃  
 *          ┃   ━    ┃
 *          ┃ >   < ┃
 *          ┃       ┃
 *          ┃... ⌒ ...  ┃
 *          ┃              ┃
 *          ┗━┓          ┏━┛
 *          ┃          ┃ Code is far away from bug with the animal protecting          
 *          ┃          ┃   神兽保佑,代码无bug
 *          ┃          ┃           
 *          ┃          ┃        
 *          ┃          ┃
 *          ┃          ┃           
 *          ┃          ┗━━━┓
 *          ┃              ┣┓
 *          ┃              ┏┛
 *          ┗┓┓┏━━━━━━━━┳┓┏┛
 *           ┃┫┫       ┃┫┫
 *           ┗┻┛       ┗┻┛
 */
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#include<set>
#include<bitset>
#include<assert.h>
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,l,r) for(int i=l;i>=r;i--)
#define link(x) for(edge *j=h[x];j;j=j->next)
#define mem(a) memset(a,0,sizeof(a))
#define ll long long
#define eps 1e-8
#define succ(x) (1LL<<(x))
#define lowbit(x) (x&(-x))
#define sqr(x) ((x)*(x))
#define mid (x+y>>1)
#define NM 25
#define nm 540005 
#define N 1000005
#define M(x,y) x=max(x,y)
const double pi=acos(-1);
const ll inf=1e12;
using namespace std;
ll read(){
    ll x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return f*x;
}



int n,m,_p,p3[NM],p[NM],num[nm],b[NM],c[nm][13],tot,_t;
bool _v[nm],a[NM][NM];
char _s[NM];
ll d[2][nm],ans[NM];


int main(){
    //freopen("data.in","r",stdin);
    p3[0]=p[0]=1;
    inc(i,1,12)p3[i]=p3[i-1]*3;
    inc(i,1,20)p[i]=p[i-1]*i;
    n=p3[12]-1;
    inc(i,0,n){
	_v[i]=true;
	for(int x=i,j=1;x;j++,x/=3)c[i][j]=x%3;
	inc(j,1,12)num[i]+=c[i][j]==1,_v[i]=_v[i]&&c[i][j]<=1;
    }
    int _=read();while(_--){
	mem(d);mem(ans);mem(b);
	m=read();n=read();_p=read();
	inc(j,1,m){
	    scanf("%s",_s+1);
	    inc(i,1,n)a[i][j]=_s[i]=='Q';
	}
	inc(i,1,n){
	    dec(j,m,1)b[i]*=3,b[i]+=a[i][j]?2:0;
	}
	tot=p3[m]-1;d[_t=0][0]=1;
	inc(i,1,n){
	    _t^=1;
	    inc(j,0,tot)if(d[_t^1][j]&&num[j]<=_p){
		int t=0;
		dec(k,m,1)if(c[j][k]==1)t=t*3+1;else t=t*3+(c[j][k]||c[b[i]][k]?2:0);
		d[_t][t]+=d[_t^1][j];
		if(num[j]<_p)inc(k,1,m)if(a[i][k]&&c[j][k]!=1){
		    t=j+(1-c[j][k])*p3[k-1];
		    d[_t][t]+=d[_t^1][j];
		}
		d[_t^1][j]=0;
	    }
	    //inc(j,0,tot)printf("%d ",f[j]);putchar('\n');
	}
	inc(j,0,tot)if(d[_t][j]&&_v[j])ans[num[j]]+=d[_t][j];
	inc(i,1,_p){
	    __int128 t=ans[i];t*=p[i];
	    if(t>inf)printf("%lld%012lld\n",(ll)(t/inf),(ll)(t%inf));
	    else printf("%lld\n",(ll)t);
	}
    }
    return 0;
}

 

 

 

Pop the Balloons

Time Limit: 7000/7000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 180    Accepted Submission(s): 63


 

Problem Description

Recently, an interesting balloon-popping game can be commonly found near the streets. The rule of this game is quite simple: some balloons are tied to cells of an n×m lattice, and you are allowed to throw k darts to prick the balloons. The more balloons you pierce, the more incredible prize you will get.

Probably because too many people have got bored with this childish game, a new variation of the game has appeared. In this variation, the balloons are replaced with more powerful ones: when a balloon explodes, strong gusts travel in four directions, blowing away all remaining balloons in the same row and column. In order to reduce the difficulty, not all cells are filled with a balloon.

For example, if you prick the yellow balloon in the following figure, then the red balloons will be blown away, with only the blue balloon remaining.
 



Now, you are given k darts. Since you are a good dart player that you can precisely throw it to any position you want, it is easy for you to use these k darts to clear all balloons (either by directly pricking, or by blowing away by other exploded balloons). Now you begin to consider: for every 1≤xk, how many different ways are there to clear all balloons with exactly x darts? Two ways are considered different if and only if there exists i, such that the positions of i-th pricked balloons differ. Note that you cannot throw the dart to an empty cell.

 

 

Input

The first line of input is a single integer T (1≤T≤100), denoting the number of test cases.

Each test case begins with a line of three integers m,n (1≤m≤12,1≤n≤20), denoting the size of the balloon lattice, and k (1≤k≤20), denoting the number of darts. The next m lines, each containing n characters, describe the balloon lattice. Each character is either '

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值