False Mirrors URAL 1152. dfs

False Mirrors URAL 1152.

题目大意:这道题的大体意思是,一个n个阳台,每个阳台上有多个怪物,a1,a2,a3……an; 然后一个人可以shoot,射中一个阳台,那么这个阳台和左右两边相邻的阳台上的怪物都会死掉,剩下的不死的怪物就会反击,每只反击一个Unit的伤害,问最小的伤害是多少? a1和an是相邻的! 假如a1和a 5之间阳台都被毁坏了,也不算数相邻的!
input:
7
3 4 2 2 1 4 1
output:
9
先射击4,受到的伤害2+1+4+1=8;再射击1,受到伤害1。总共8+1=9;
题目分析:直接dfs搜最优解。

#include <bits/stdc++.h>
using namespace std;

const int maxn = 1e3 + 10;
const int inf = 0x3f3f3f3f;
int data[maxn], Max;
int n;
bool vis[maxn];

void dfs(int sum, int damage)
{
   // printf("%d\n", sum);
    if(sum == 0)
    {
        Max = min(damage, Max);
        return ;
    }

    if(damage > Max) return ;

    for(int i = 0; i < n; i++)
    {
        int Front = (i == 0 ? n - 1 : i - 1);
        int Back = (i == n - 1 ? 0 : i + 1);
        int v = sum - data[i] - data[Front] - data[Back];
        if(data[i] + data[Front] + data[Back])
        {

            int td = damage + v;
            int c = data[i], c1 = data[Front], c2 = data[Back];
            data[i] = data[Front] = data[Back] = 0;
            dfs(v, td);
            data[i] = c;
            data[Front] = c1;
            data[Back] = c2;
        }

    }
}

int main()
{
    int sum = 0;
    scanf("%d", &n);
    for(int i = 0; i < n; i++)
    {
        scanf("%d", &data[i]);
        sum += data[i];
    }

    Max = inf;
    dfs(sum, 0);
    printf("%d\n", Max);
}

后来看了梁同学的做法,发现可以状压记录状态+DFS,这样比单纯的DFS快很多。
代码:

#include <bits/stdc++.h>
using namespace std;

const int maxn = 1e3 + 10;
const int inf = 0x3f3f3f3f;
int data[maxn], n, dp[1 << 21];

int dfs(int now)
{
    if(!now) return 0;
    if(dp[now] != inf) return dp[now];
    for(int i = 0; i < n; i++) {
        if(!(now & (1 << i))) continue;
        int nextnow = now;
        int Front = (i == 0 ? n - 1 : i - 1);
        int Back = (i == n - 1 ? 0 : i + 1);

        nextnow = (nextnow & (~(1 << i)));
        nextnow = (nextnow & (~(1 << Front)));
        nextnow = (nextnow & (~(1 << Back)));

        int hurt = 0;
        for(int j = 0; j < n; j++)
        {
            if(nextnow & (1 << j)) hurt += data[j];
        }
        dp[now] = min(dfs(nextnow) + hurt, dp[now]);
    }
    return dp[now];
}

int main()
{
    memset(dp, inf, sizeof(dp));
    scanf("%d", &n);
    for(int i = 0; i < n; i++)
        scanf("%d", &data[i]);

    printf("%d\n", dfs((1 << n) - 1));
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值