HDU

来源:互联网 发布:中国联通宽带提速软件 编辑:程序博客网 时间:2024/05/21 06:33

题意
在一张n*m的地图中,1表示有树,0表示没有树(也不能走)
DOTA中有一个英雄任务是去吃树(打防御塔)。问,他吃完所有树,并且相同地方不走两次的回路有几条(即哈密顿回路)。

思路
求哈夫曼回路,用插头dp
如果不知道插头dp,可以看看这里

参考代码

#include<cstdio>#include<algorithm>#include<iostream>#include<cstring>#include<cmath>using namespace std;int n,m;long long dp[15][15][1<<13]; // dp[行][列][状态] 里面的值代表 当前位置如果本状态 有多少方案数 int mp[15][15];int main(){    int t,ts=0;    scanf("%d",&t);    while(t--){        scanf("%d%d",&n,&m);        for(int i=1;i<=n;i++){            for(int j=1;j<=m;j++){                scanf("%d",&mp[i][j]);            }        }        memset(dp,0,sizeof(dp));        dp[0][m][0]=1;        for(int i=1;i<=n;i++){  //枚举每一行             for(int k=0;k<(1<<m);k++){      //初始化本行第零个元素 即加入第一个向右插头                 dp[i][0][k<<1]=dp[i-1][m][k];            }            for(int j=1;j<=m;j++){ //枚举本行的每个元素                 int r=1<<j;     // 用于检查向右的插头                 int d=1<<(j-1); // 用于检查向下的插头                for(int k=0;k<(1<<m+1);k++){ //枚举可以的状态                     if(mp[i][j]){ //有树要吃                         if((r&k)&&(d&k)){   //有两个插头                             dp[i][j][k]=dp[i][j-1][k-r-d]; // 没有插头传递过来                         }                        else if((r&k)==0&&(d&k)==0){ // 没有插头                             dp[i][j][k]=dp[i][j-1][k+r+d]; //说明 有两个插头传递过来                         }                        else{ //有一个插头                             dp[i][j][k]=dp[i][j-1][k^r^d]+dp[i][j-1][k]; // 传递一个插头                         }                    }                    else{//没有树                         if((r&k)==0&&(d&k)==0){  //没有插头                             dp[i][j][k]=dp[i][j-1][k]; //无需传递插头                         }                        else{                            dp[i][j][k]=0;  // 不可能有插头                         }                    }                }             }        }        printf("Case %d: There are %lld ways to eat the trees.\n",++ts,dp[n][m][0]);    }    return 0;}