HDU 4539 郑厂长系列故事——排兵布阵(状态压缩dp)

来源:互联网 发布:php mysql 三表联查 编辑:程序博客网 时间:2024/05/01 10:25
 一天,郑厂长带着他的军队来到了一个n*m的平原准备布阵。
  根据以往的战斗经验,每个士兵可以攻击到并且只能攻击到与之曼哈顿距离为2的位置以及士兵本身所在的位置。当然,一个士兵不能站在另外一个士兵所能攻击到的位置,同时因为地形的原因平原上也不是每一个位置都可以安排士兵。
  现在,已知n,m 以及平原阵地的具体地形,请你帮助郑厂长计算该阵地,最多能安排多少个士兵。
 

Input
输入包含多组测试数据;
每组数据的第一行包含2个整数n和m (n <= 100, m <= 10 ),之间用空格隔开;
接下来的n行,每行m个数,表示n*m的矩形阵地,其中1表示该位置可以安排士兵,0表示该地形不允许安排士兵。
 

Output
请为每组数据计算并输出最多能安排的士兵数量,每组数据输出一行。
 

Sample Input
6 60 0 0 0 0 00 0 0 0 0 00 0 1 1 0 00 0 0 0 0 00 0 0 0 0 00 0 0 0 0 0
 

Sample Output
2

读懂这个题先了解一下曼哈顿距离|x1-x2|+|y1-y2| 所以上下左右和斜对角都不能取,这题我用的思路是类似于方格取数的,具体看代码吧

ps:当时想到用二分匹配就最大独立集...就一个简单的匈牙利..然后一直wa,后来....“这题不能够进行拆点构图,因为从一个点引出去的边的端点相互之间是可以连边的,这就相当于一个成环了,而有环的图又怎么划分出两个内部没有边的二分图呢?”摘自点击打开链接,网上找到的唯一一个也用了二分匹配的...其实我也不清楚他的解释什么意思:-(,二分图学的不到家

题目链接:点击打开链接

代码注释:

<pre name="code" class="cpp">#include<iostream>#include<cstring>using namespace std;int q[200],dp[105][200][200],map[105][15],n,mm;//涉及到上上行这里dp要开到三维void solve(){    int m=0;    for(int i=0; i<(1<<mm); i++)        if((i&(i<<2))==0)//行相邻为2的满足的存下来            q[m++]=i;    memset(dp,0,sizeof(dp));    for(int i=1; i<=n; i++)        for(int j=0; j<m; j++)        {            int sum=0,flag=0;            for(int k=0; k<mm; k++)            {                if(q[j]&(1<<k))//在q[j]这个状态中找到都取了哪些数                {                    if(map[i][k]==0)                    flag=1;//这里可以直接break出来了,省点时间                    else                        sum++;//本行放了几个兵                }            }            if(flag)//只要有一个该放兵的位置没放兵就跳过这个状态                continue;            for(int k=0; k<m; k++)            {                if(!(q[j]&(q[k]<<1))&&!(q[j]&(q[k]>>1)))//a[j]本行状态q[k]上行状态取&为0表示对角处不取                {                    for(int w=0; w<m; w++)//q[w]上上行的状态                    {                        if(!(q[j]&q[w]))//上上行处不取                        {                            dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][w]+sum);//状态转移方程,sum为本行的人数                        }                    }                }            }        }    int ans=0;    for(int i=0; i<m; i++)        for(int j=0; j<m; j++)            ans=max(ans,dp[n][i][j]);    cout<<ans<<endl;}int main(){    while(cin>>n>>mm)    {        for(int i=1; i<=n; i++)            for(int j=0; j<mm; j++)                cin>>map[i][j];        solve();    }}


0 0
原创粉丝点击