HDU 1693(状态压缩 插头DP)
生活随笔
收集整理的這篇文章主要介紹了
HDU 1693(状态压缩 插头DP)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
?
我們引用國家隊2008年陳丹琦的大作——《基于連通性狀態壓縮的動態規劃問題》,上面對于插頭、輪廓線的概念有詳細的解釋,不再贅述。
?
我們使用一個三維數組,前兩維表示所在的格子,后一維表示輪廓線的狀況,值為方案數。
?
在每一行開始前,我們需要把上一行最右的輪廓線轉換為這一行最左的輪廓線,因此執行一次左移操作(實際上輪廓線是進行了向右的一次滑動)
?
?
?
然后枚舉所在單元格對每個輪廓線的影響 在論文中我們可以發現輪廓線總是包圍一個格子的上部分和左部分 我們認為如果有通路與輪廓線重合則為1否則為0
?
?
?
?
因此很容易想象出來(當然也可以看論文)各個狀態之間的轉移關系 對于可通行的格子 分部分覆蓋和全部覆蓋以及全部不覆蓋的情況討論
?
對不可通行的格子必須將不可能的覆蓋方案置為0 到最后的結果就是所求的方案了即dp[m][n][0]
?
感謝DK大牛的指導 本人5天來的苦思冥想終于得到了成果 1693 0ms 排行統計第一....
?
以下為本人代碼:
?
?
#include?<iostream>using?namespace?std;
typedef?__int64?LL;
LL?dp[12][12][1<<12];
long?hash[12][12];
int?main()
{
????long?T;
????long?b=1;
????scanf("%ld",&T);
????while?(T--)
????{
????????long?i,j,k,m,n;
????????scanf("%ld?%ld",&m,&n);
????????for?(i=1;i<=m;++i)
????????{
????????????for?(j=1;j<=n;++j)
????????????{
????????????????scanf("%ld",&hash[i][j]);
????????????}
????????}
????????dp[0][n][0]=1;
????????for?(i=1;i<=m;++i)
????????{
????????????long?len=1<<n;
????????????for?(j=0;j<len;++j)
????????????{
????????????????dp[i][0][j<<1]=dp[i-1][n][j];
????????????}
????????????
????????????for?(j=1;j<=n;++j)
????????????{
????????????????len=(1<<n<<1);
????????????????for(k=0;k<len;++k)
????????????????{
????????????????????long?p=1<<j;
????????????????????long?q=p>>1;
????????????????????
????????????????????bool?x=p&k;
????????????????????bool?y=q&k;
????????????????????if?(hash[i][j])
????????????????????{
????????????????????????dp[i][j][k]=dp[i][j-1][k^p^q];
????????????????????????if?(x!=y)
????????????????????????{
????????????????????????????dp[i][j][k]+=dp[i][j-1][k];
????????????????????????}
????????????????????}
????????????????????else
????????????????????{
????????????????????????if?(x==0&&y==0)
????????????????????????{
????????????????????????????dp[i][j][k]=dp[i][j-1][k];
????????????????????????}
????????????????????????else
????????????????????????{
????????????????????????????dp[i][j][k]=0;
????????????????????????}
????????????????????}
????????????????}
????????????}
????????}
????????printf("Case?%ld:?There?are?%I64d?ways?to?eat?the?trees.\n",b++,dp[m][n][0]);
????}
????return?0;
}
?
?
以下為DK大人的sample代碼,我加上了注釋:
?
#include<iostream>using?namespace?std;
int?mat[100][100];
__int64?dp[12][12][1<<12];
int?main()
{
????//?freopen("1.txt","r",stdin);
????int?zu;
????int?g=1;
????scanf("%d",&zu);
????while(zu--)
????{
????????int?m,n;
????????scanf("%d%d",&m,&n);
????????int?i,j,k;
????????for(i=1;i<=m;i++)
????????????for(j=1;j<=n;j++)
????????????????scanf("%d",&mat[i][j]);
????????????//memset(dp,0,sizeof(dp));
????????????dp[0][n][0]=1;
????????????for(i=1;i<=m;i++)
????????????{
????????????????for(j=0;j<(1<<n);j++)
????????????????????dp[i][0][j<<1]=dp[i-1][n][j];
????????????????//把最右邊的去掉?把所有的狀態拉到下一行并進行合理的改變(注意最左邊的是低位所代表的數)?
????????????????//上一行最右邊的邊格一定不與輪廓線重合?下一行最左邊的邊格也一定不與輪廓線重合?
????????????????//所以進行的是上一行所有狀態(也就是輪廓線)向右的一次滑動
????????????????????for(j=1;j<=n;j++)//枚舉決策線的拐向
????????????????????{
????????????????????????for(k=0;k<(1<<n<<1);k++)//枚舉輪廓線
????????????????????????{
????????????????????????????int?p=1<<j;//第j個輪廓段(上)
????????????????????????????int?q=p>>1;//第j-1個輪廓段(左)
????????????????????????????bool?x=k&p;//左輪廓是否與通路相交
????????????????????????????bool?y=k&q;//上輪廓是否與通路相交
????????????????????????????
????????????????????????????//判斷輪廓線在[i,j]為拐向時的分布?每個格子有1<<n<<1種?多階段決策
????????????????????????????
????????????????????????????if(mat[i][j])//如果該單元可以通行
????????????????????????????{
????????????????????????????????dp[i][j][k]=dp[i][j-1][k^p^q];//必然有一個通路連接上一個格的通路
????????????????????????????????if(x!=y)
????????????????????????????????????dp[i][j][k]+=dp[i][j-1][k];//有一處新覆蓋則有另外的一種情況
????????????????????????????}
????????????????????????????else//否則為障礙格子
????????????????????????????{
????????????????????????????????if(x==0&&y==0)//通路與輪廓線不相交
????????????????????????????????????dp[i][j][k]=dp[i][j-1][k];//直接轉移
????????????????????????????????else
????????????????????????????????????dp[i][j][k]=0;//通路與輪廓線相交的方案一定為0
????????????????????????????}
????????????????????????}
????????????????????}
????????????}
????????????printf("Case?%d:?There?are?%I64d?ways?to?eat?the?trees.\n",g++,dp[m][n][0]);
????}
????return?0;
}?
轉載于:https://www.cnblogs.com/zhuangli/archive/2008/09/04/1283753.html
總結
以上是生活随笔為你收集整理的HDU 1693(状态压缩 插头DP)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 用白凉粉做果冻的原理
- 下一篇: 面向接口编程详解(三)——模式研究