hdu 4281 judges' response

hdu 4281 judges' response

这个题比赛的时候没有搞出来,当时思路太乱了,而且样例都没仔细看,就开始敲了,导致敲完了看样例才发现题意理解错了,T_T


问1: 抽象成给你n(你<=15)个物品 (物品的体积为C[ i ]) ,问至少用几个箱子把这n个物品装满

问2: 预处理出一个人在服务时间小于等于m的情况下,服务集合为state 的最短行走距离,然后就和问1一样背包就行了


#include<stdio.h>
#include<string.h>
#include<iostream>
#include<queue>
#include<cmath>

using namespace std;
int d[16][16],c[16],n,m;
int dp1[1<<16],dp2[1<<16],x[16],y[16];

int ans[1<<16],sum[1<<16],dp[1<<16][16];
bool vis[1<<16][16];

int solve1()
{
    dp1[0]=0;
    for(int i=1;i<(1<<n);i++)
    {
        int tmp=0;
        for(int j=0;j<n;j++)
          if(i&(1<<j)) tmp+=c[j];
        if(tmp<=m) dp1[i]=1;
        else dp1[i]=-1;
    }
    int lim=(1<<n)-1;
    for(int i=0;i<(1<<n);i++)
       if(dp1[i]>=0){
           int sub=i^lim;
           for(int j=sub;j;j=(j-1)&(sub))
             if(dp1[j]>=0){
                if(dp1[i|j]==-1||dp1[i|j]>dp1[i]+dp1[j]) dp1[i|j]=dp1[i]+dp1[j];
             }
       }
    return dp1[lim];
}

int solve2()
{
    memset(sum,0,sizeof(sum));
    for(int i=1;i<(1<<n);i++)
    for(int j=0;j<n;j++)
       if(i&(1<<j)) sum[i]+=c[j];
    queue<pair<int,int> > q;
    q.push(make_pair(0,0));
    memset(vis,0,sizeof(vis));
    memset(dp,-1,sizeof(dp));
    dp[0][0]=c[0];
    for(;!q.empty();q.pop())
    {
        int s=q.front().first,u=q.front().second;
        vis[s][u]=0;
        for(int j=0;j<n;j++)
          if(!(s&(1<<j))&&sum[s|(1<<j)]<=m){
               if(dp[s|(1<<j)][j]==-1||dp[s|(1<<j)][j]>dp[s][u]+d[u][j]){
                  dp[s|(1<<j)][j]=dp[s][u]+d[u][j];
                  if(!vis[s|(1<<j)][j]) q.push(make_pair(s|(1<<j),j)),vis[s|(1<<j)][j]=1;
               }
          }
    }
    memset(ans,-1,sizeof(ans));
    for(int i=0;i<(1<<n);i++)
    for(int j=0;j<n;j++)
      if(dp[i][j]!=-1){
         if(ans[i]==-1||ans[i]>dp[i][j]+d[j][0]) ans[i]=dp[i][j]+d[j][0];
      }
    ans[0]=0;

    int lim=(1<<n)-1;
    for(int i=0;i<(1<<n);i++)
    if(ans[i]>=0)
    {
        int sub=lim^i;
        for(int j=sub;j;j=(j-1)&(sub))
         if(ans[j]>=0){
           if(ans[i|j]==-1||ans[i|j]>ans[i]+ans[j]) ans[i|j]=ans[i]+ans[j];
         }
    }
    return ans[lim];
}

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


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值