HDU 4281 Judges' response

状态压缩dp,经典MTSP问题,第一问比较容易求,先求出满足情况的状态放在了mov里面,然后模拟0-1背包的过程求出最少用多少judge。第二问就比较复杂了,第二问要求我们算出最短的时间,即最短总路程。这样的话就比较难求了。。。第二问看了一下网上大神的代码才懂的。。。汗。。。第二问,dt[i][j],表示当状态为i(注意:i & 1 == 1)时, 最后一个走过的节点是j时最短路径, best[i] 表示状态完成状态 i 需要的最短路径。然后具体实现还是看代码吧。。。

#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<cstdio>
#include<cmath>

#define SL strlen
#define PB push_back
#define LL long long
#define INF 0X3f3f3f3f
#define CLR(a, b) memset(a, b, sizeof(a))

using namespace std;

const int N = 17;

struct Point
{
    int x, y;
}p[N];

int dp[1 << N], c[N];
int dt[1 << N][N], best[1 << N];
int g[N][N];
vector<int> mov;
int n, m, i, j, k;

int len(Point a, Point b)
{
    return ceil(sqrt((double)(a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)));
}

bool ok(int k)
{
    int ret = 0; j = 0;
    while(k)
    {
        if(k & 1)
        {
            ret += c[j];
        }
        k >>= 1;
        j ++;
    }
    return ret <= m;
}

void input()
{
    for(i = 0; i < n; i ++)
    {
        scanf("%d%d", &p[i].x, &p[i].y);
    }
    for(i = 0; i < n; i ++)
    {
        scanf("%d", &c[i]);
    }
}

void work()
{
    for(i = 0; i < n; i ++)
    {
        for(j = 0; j < n; j ++)
        {
            g[i][j] = len(p[i], p[j]);
        }
    }
    mov.clear();
    for(i = 1; i < (1 << n); i ++)
    {
        if(ok(i)) mov.PB(i);
    }
}

bool solve()
{
    CLR(dp, INF);
    dp[0] = 0;
    for(i = 0; i < mov.size(); i ++)
    {
        for(j = (1 << n) - 1; j >= 1; j --)
        {
            if((j & mov[i]) == mov[i])
            {
                dp[j] = min(dp[j], dp[j ^ mov[i]] + 1);
            }
        }
    }
    if(dp[(1 << n) - 1] == INF) { printf("-1 ");return 0; }
    //else printf("%d ", dp[(1 << n) - 1]); return 1;
}

void TSP()
{
    CLR(best, INF);
    CLR(dt, INF);
    dt[1][0] = 0;
    for(i = 0; i < mov.size(); i ++)
    {
        for(j = 0; j < n; j ++)
        {
            if((1 << j) & mov[i])
            {
                best[mov[i]] = min(best[mov[i]], dt[mov[i]][j] + g[j][0]);
                for(k = 0; k < n; k ++)
                {
                    if(!((1 << k) & mov[i]))
                    {
                        dt[mov[i] | (1 << k)][k] = min(dt[mov[i] | (1 << k)][k], dt[mov[i]][j] + g[j][k]);
                    }
                }
            }
        }
    }
    for(i = 1; i < (1 << n); i ++)
    {
        if(i & 1) for(j = i & (i - 1); j; j = i & (j - 1))
        {
            best[i] = min(best[i], best[j] + best[(i ^ j) | 1]);
        }
    }
    printf("%d\n", best[(1 << n) - 1]);
}

int main()
{
    //freopen("input.txt", "r", stdin);
    while(scanf("%d%d", &n, &m) != EOF)
    {
        input();
        work();
        if(solve()) TSP();
        else puts("-1");
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值