HDU 4281 Judges' response(12年天津 MTSP问题)

来源:岁月联盟 编辑:exp 时间:2012-09-12

题目:给出N个人,其中0号是裁判的位置,剩下有N-1的人提问,裁判需要去回答问题,每个人有一个val,每个裁判能拿到的val的上限为K。问题最少需要几个裁判,以及最少时间

 


第一问可以状态压缩DP解决,dp[i]表示状态i需要几个裁判,也可以排序之后贪心。从大到小,尽可能地装入一个盒子。

第二问就是多个TSP问题,dp[i][j]表示当前位置 在i,可行状态为j的最小费用,best[i]表示对于状态i的最小费用(而且是一个完整状态,裁判都回到原点),因为之前TSP中是求的可行状态,也就是每个裁判的上限不能超过K。之后就是枚举所有状态,对于一个状态,枚举他的所有子集,见代码中的位运算部分。而且两个子集中必须要包含0号结点,因为每个裁判都是从0出发的

 
[cpp]
#include<iostream>  
#include<cstdio>  
#include<map>  
#include<cstring>  
#include<cmath>  
#include<vector>  
#include<algorithm>  
#include<set>  
#define inf 1<<28  
#define M 100005  
#define N 55  
#define Min(a,b) ((a)<(b)?(a):(b))  
#define Max(a,b) ((a)>(b)?(a):(b))  
#define pb(a) push_back(a)  
#define mem(a,b) memset(a,b,sizeof(a))  
#define LL long long  
#define MOD 1000000007  
using namespace std; 
struct Point{ 
    int x,y; 
}p[20]; 
int n,m,val[20],path[20][20]; 
int dp[16][1<<16]; 
int best[1<<16],ok[1<<16]; 
int dist(Point p1,Point p2){ 
    return ceil(sqrt((double)(p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y))); 

void Get_dist(){ 
    for(int i=0;i<n;i++) for(int j=0;j<n;j++) path[i][j]=dist(p[i],p[j]); 

void Init(){ 
    for(int i=0;i<n;i++) 
        for(int j=0;j<(1<<n);j++) 
            dp[i][j]=inf; 
    for(int i=0;i<(1<<n);i++) 
        best[i]=inf; 
    dp[0][1]=0; 

int check(int state){ 
    int sum=0; 
    for(int i=0;i<n;i++) 
        if(state&(1<<i)) 
            sum+=val[i]; 
    return sum<=m; 

bool cmp(int a,int b){return a>b;} 
int slove(){ 
    int v[20]; 
    memcpy(v,val,sizeof(val)); 
    sort(v,v+n,cmp); 
    if(v[0]>m) return -1; 
    int flag[20]; 
    mem(flag,0); 
    int cnt=0; 
    for(int i=0;i<n;i++){ 
        if(flag[i]) continue; 
        int tmp=0;   
        for(int j=i;j<n;j++){ 
            if(flag[j]==0){ 
                if(tmp+v[j]<=m){ 
                    flag[j]=1; 
                    tmp+=v[j]; 
                } 
            } 
        } 
        cnt++; 
    } 
    return cnt; 

int TSP(){ 
    for(int i=0;i<(1<<n);i++){ 
        if(ok[i]) 
            for(int j=0;j<n;j++) 
                if(i&(1<<j)){ 
                    best[i]=min(best[i],dp[j][i]+path[j][0]); 
                    for(int k=0;k<n;k++) 
                        if(!(i&(1<<k))) 
                            dp[k][i|(1<<k)]=min(dp[k][i|(1<<k)],dp[j][i]+path[j][k]); 
                } 
    } 
    for(int i=0;i<(1<<n);i++) 
        if(i&1) 
            for(int j=i&(i-1);j;j=i&(j-1)) 
                best[i]=min(best[i],best[j]+best[(i-j)|1]); 
    return best[(1<<n)-1]; 

 
int main(){ 
    while(scanf("%d%d",&n,&m)!=EOF){ 
        for(int i=0;i<n;i++) scanf("%d%d",&p[i].x,&p[i].y); 
        for(int i=0;i<n;i++) scanf("%d",&val[i]); 
        for(int i=0;i<(1<<n);i++)  ok[i]=check(i); 
        Get_dist(); 
        Init(); 
        int ans1=slove(); 
        if(ans1==-1) {printf("-1 -1/n");continue;} 
        printf("%d %d/n",ans1,TSP()); 
    } 
    return 0; 

#include<iostream>
#include<cstdio>
#include<map>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
#include<set>
#define inf 1<<28
#define M 100005
#define N 55
#define Min(a,b) ((a)<(b)?(a):(b))
#define Max(a,b) ((a)>(b)?(a):(b))
#define pb(a) push_back(a)
#define mem(a,b) memset(a,b,sizeof(a))
#define LL long long
#define MOD 1000000007
using namespace std;
struct Point{
 int x,y;
}p[20];
int n,m,val[20],path[20][20];
int dp[16][1<<16];
int best[1<<16],ok[1<<16];
int dist(Point p1,Point p2){
 return ceil(sqrt((double)(p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y)));
}
void Get_dist(){
 for(int i=0;i<n;i++) for(int j=0;j<n;j++) path[i][j]=dist(p[i],p[j]);
}
void Init(){
 for(int i=0;i<n;i++)
  for(int j=0;j<(1<<n);j++)
   dp[i][j]=inf;
 for(int i=0;i<(1<<n);i++)
  best[i]=inf;
 dp[0][1]=0;
}
int check(int state){
 int sum=0;
 for(int i=0;i<n;i++)
  if(state&(1<<i))
   sum+=val[i];
 return sum<=m;
}
bool cmp(int a,int b){return a>b;}
int slove(){
 int v[20];
 memcpy(v,val,sizeof(val));
 sort(v,v+n,cmp);
 if(v[0]>m) return -1;
 int flag[20];
 mem(flag,0);
 int cnt=0;
 for(int i=0;i<n;i++){
  if(flag[i]) continue;
  int tmp=0; 
  for(int j=i;j<n;j++){
   if(flag[j]==0){
    if(tmp+v[j]<=m){
     flag[j]=1;
     tmp+=v[j];
    }
   }
  }
  cnt++;
 }
 return cnt;
}
int TSP(){
 for(int i=0;i<(1<<n);i++){
  if(ok[i])
   for(int j=0;j<n;j++)
    if(i&(1<<j)){
     best[i]=min(best[i],dp[j][i]+path[j][0]);
     for(int k=0;k<n;k++)
      if(!(i&(1<<k)))
       dp[k][i|(1<<k)]=min(dp[k][i|(1<<k)],dp[j][i]+path[j][k]);
    }
 }
 for(int i=0;i<(1<<n);i++)
  if(i&1)  www.2cto.com
   for(int j=i&(i-1);j;j=i&(j-1))
    best[i]=min(best[i],best[j]+best[(i-j)|1]);
 return best[(1<<n)-1];
}

int main(){
 while(scanf("%d%d",&n,&m)!=EOF){
  for(int i=0;i<n;i++) scanf("%d%d",&p[i].x,&p[i].y);
  for(int i=0;i<n;i++) scanf("%d",&val[i]);
  for(int i=0;i<(1<<n);i++)  ok[i]=check(i);
  Get_dist();
  Init();
  int ans1=slove();
  if(ans1==-1) {printf("-1 -1/n");continue;}
  printf("%d %d/n",ans1,TSP());
 }
 return 0;
}