andre_joy

导航

hdu 4281

地址:http://acm.hdu.edu.cn/showproblem.php?pid=4281

题意:有n个任务等待完成,每个任务有位置,所需时间,每个人最多m分钟。

   第一问是求这些任务最少几个人完成;第二问是给无数个人,问最少需要多少分钟完成所有任务,并且每个人上限还是m。

mark:第一问可以状态dp,可以01背包记录一下,然后回溯。

    第二问参见了大牛的做法,先状态dp,然后暴力搜索一下。

   今天才了解到状态压缩dp可以有两种方式写,第一种是从前往后扫一遍,每次转换这个状态能够到达的状态(因为状态肯定是由值小的到值大的)

                       第二种是用队列来写,能够到达的状态都进队。类似与bfs。

代码:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <queue>
#define s(x) ((x)*(x))

using namespace std;

const int maxn = (1 << 16);
const int INF = 10000000;
int d[20][20], sum[maxn];
int n,m;
int x[20],y[20],c[20];

int min(int a, int b) {return a < b ? a : b;}

void solve1()
{
    int dp1[maxn], dp2[maxn];
    int i,j,k;
    memset(dp1, -1, sizeof(dp1));
    dp1[0] = dp2[0] = 0;
    for(i = 0; i < (1 << n); i++)
    {
        if(dp1[i] < 0) continue;
        for(j = 0; j < n; j++)
        {
            if(i&(1<<j)) continue;
            int ss = (i|(1<<j));
            int d1,d2;
            if(dp2[i] >= c[j]) d1 = dp1[i], d2 = dp2[i]-c[j];
            else d1 = dp1[i]+1, d2 = m-c[j];
            if(dp1[ss] < 0 || dp1[ss] > d1 || dp1[ss] == d1 && dp2[ss] < d2)
                dp1[ss] = d1, dp2[ss] = d2;
        }
    }
    printf("%d ", dp1[i-1]);
}

int dp[maxn][20], vis[maxn][20];
int ans[maxn];

void solve2()
{
    int i,j,k;
    queue<int> q;
    for(i = 0; i < n; i++)
        for(j = 0; j < n; j++)
        {
            if(i == j) d[i][j] = 0;
            else d[i][j] = ceil(sqrt(s(x[i]-x[j])+s(y[i]-y[j])));
        }
    for(i = 0; i < (1 << n); i++)
    {
        sum[i] = 0;
        for(j = 0; j < n; j++)
            if(i&(1<<j)) sum[i] += c[j];
    }
    memset(dp, -1, sizeof(dp));
    dp[0][0] = 0;
    vis[0][0] = 1;
    q.push(0);
    while(!q.empty())
    {
        int qq = q.front();
        q.pop();
        int s1 = qq%70000, s2;
        qq /= 70000;
        vis[s1][qq] = 0;
        for(i = 0; i < n; i++)
        {
            if(s1&(1<<i)) continue;
            s2 = s1|(1<<i);
            if(sum[s2] > m) continue;
            if(dp[s2][i] < 0 || dp[s2][i] > dp[s1][qq]+d[i][qq])
            {
                dp[s2][i] = dp[s1][qq]+d[i][qq];
                if(!vis[s2][i])
                {
                    vis[s2][i] = 1;
                    q.push(i*70000+s2);
                }
            }
        }
    }
    memset(ans, -1, sizeof(ans));
    for(i = 0; i < (1 << n); i++)
        for(j = 0; j < n; j++)
        {
            if(i&(1<<j) && dp[i][j] > 0)
                if(ans[i] < 0 || ans[i] > dp[i][j]+d[0][j])
                    ans[i] = dp[i][j]+d[0][j];
        }
    k = (1 << n)-2;
    for(i = 1; i < (1 << n); i++, k--)
    {
        if(ans[i] < 0) continue;
        for(j = k; j; j = (j-1)&k)
        {
            if(ans[j] < 0) continue;
            if(ans[i+j] < 0 || ans[i+j] > ans[i]+ans[j])
                ans[i+j] = ans[i]+ans[j];
        }
    }
    printf("%d\n", ans[(1 << n)-1]);
}

int main()
{
    int i;
    while(~scanf("%d%d", &n, &m))
    {
        for(i = 0; i < n; i++)
            scanf("%d%d", x+i, y+i);
        for(i = 0; i < n; i++)
            scanf("%d", c+i);
        for(i = 0; i < n; i++)
            if(c[i] > m)
            {
                printf("-1 -1\n");
                break;
            }
        if(i < n) continue;
        solve1();
        solve2();
    }
    return 0;
}

posted on 2012-09-11 11:49  andre_joy  阅读(235)  评论(0编辑  收藏  举报