HDU 4281(01 背包+ 多旅行商问题)

HDU  4281 Judges' response


 

Problem Description
  The contest is running and the judges is busy watching the progress of the contest. Suddenly, N - 1 (N <= 16) contestants hand up their hand at the same time. The judges should go to answer the contestants' question one by one. The judges already foresee that answering contest i's question would cost Ci minutes. In order to serve all the contestant, each judges is assigned to serve some subset of the contestants. As the judges have limited patience, each one of them can serve the contestants for no more than M minutes.
  You are asked to solve two problems:
  1. At least how many judges should be sent so that they can serve all the contestants? (Because the judges have limited patience, each one of them cannot serve too many contestants.)
  2. If there are infinite number of judges, how to assign the route for each judge so that the sum of their walking time is minimized? Each contestant i is reside in place (xi, yi), the judges are in place (x1, y1). Assuming the walking speed of the judge is 1.
 

 

Input
  There are several test cases, Each case begin with two integer N, M(with the meaning in the above context, 2 <= N <= 16, 0 <= M <= 100000).
  Then N lines follow and line i will contain two numbers x, y(0 <= x, y <= 1000), indicating the coordinate of place i.
  Then another N lines follow and line i will contain numbers Ci(0 <= Ci <= 1000), indicating the time to solve contestant i's question. C1 will 0 as place 1 is for the judges.
  
  The distance between place i and place j is defined as ceil(sqrt((xi - xj) ^ 2 + (yi - yj) ^ 2)). (ceil means rounding the number up, e.g. ceil(4.1) = 5)
 

 

Output
  For each case, output two numbers. The first is the minimum number of judges for question 1. The second is the minimum sum of walking time for question 2.
  If it's impossible to serve all the contestants, please output -1 -1 instead.
 

 

Sample Input
3 3 0 0 0 3 0 1 0 1 2 3 2 0 0 0 3 0 1 0 1 2 3 1 0 0 0 3 0 1 0 1 2    16 35 30 40 37 52 49 49 52 64 31 62 52 33 42 41 52 41 57 58 62 42 42 57 27 68 43 67 58 48 58 27 37 69 0 19 30 16 23 11 31 15 28 8 8 7 14 6 19 11
 

 

Sample Output
1 6 2 8 -1 -1 8 467
 

 

Source
 
题意 : 有n-1(有一个为裁判)个人参加比赛,每个人都有一个w的问题需要问裁判,每个裁判只能回答m的问题,1.问最少派多少裁判能在最短时间内解决所有问题?2.问怎么样安排会使裁判走的总路线最短
 
输入 : n m 指 n-1个参赛者 裁判只能回答m的问题 n个坐标 第一个为裁判 其它为参赛者 接下来 n-1行每个参赛者的问题值
 
 1 . 类似 POJ - 2923 进制压缩 + 01包就能解决
2.看网上大佬博客都说是旅行商问题 非常经典(其实我还不知道..这是啥玩意) 
  解决方法 首先枚举所有一个人走完所有(能一个人解决完)情况 用best[]记录所有每种情况中用的最少的 转移方程 best[i]= min( best[i] , temp[j][i] +dis[j][0])
 temp[j][i] 代表 走 i 情况时停在了 j 点 ,最优= min(本身,停到j 点的路+j点回去的路 ) 那么temp怎么弄成那样呢 temp[停点][方案 |(使人数+1)]=名(temp[停点][方案(使人数+1的方案)]temp[停点][方案]+dis[p][加的点] ),这样三层循环就能找到所有(能一个人解决完)情况,然后就可以找第二问的答案了 遍历所有情况(这里指所(不再是一个人)),就是所有情况往一起拼, 必须是奇数在才能往一起拼,因为必须得是从 0点出发也就是二进制的末尾必须是1 然后输出best[(1<<n)-1 ]就行了  
 
  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define inf 0x3f3f3f3f
  4 int n,m,len;;
  5 int dis[18][18]; // 存点之间距离 
  6 int val[20]; //每个人需要的时间 
  7 int  vis[1<<17]; //用来存一个人能判完的所有情况 
  8 int tem[1<<17][20]; // tem[i][j] 表示 在i的情况下最后到j点需要的最短时间 
  9 int dp[1<<17];  //用于求每种状态所需要的最少裁判个数 
 10 int best[1<<17]; //用于存每种状态需要走的最少距离 
 11 int get_dis(int x,int y,int x1,int y1) //计算两点间距离 以为时间都是整数,为了到达直接向上取整 
 12 {
 13     return ceil(sqrt((x-x1)*(x-x1)+(y1-y)*(y1-y)));
 14 }
 15 bool judge(int x)  //判断一个人能解决完的所有情况   
 16 {    
 17     int sum=0;
 18     for(int i=0;i<n;i++)
 19     {
 20         if(x&(1<<i))
 21         {    
 22             sum+=val[i];
 23         }
 24     }
 25     
 26     return sum<=m;
 27     
 28 }
 29 int DP() //计算裁判人数 
 30 {    
 31 
 32     memset(dp,inf,sizeof(dp));
 33     dp[0]=0;
 34     for(int i=0;i<len;i++)
 35     {
 36         
 37         int k=vis[i];
 38         for(int j=(1<<n)-1;j>=0;j--)   //枚举所有状态 类似01背包 
 39         {    
 40             if(dp[j]==inf) continue;
 41             if(!(k&j)) dp[j|k]=min(dp[j|k],dp[j]+1);  //找不交叉的方案转移 
 42                 
 43         }
 44         
 45         
 46     }
 47     
 48     return dp[(1<<n)-1]==inf?-1:dp[(1<<n)-1];
 49     
 50     
 51 }
 52 void TSP()  
 53 {
 54     
 55     memset(tem,inf,sizeof(tem));
 56     memset(best,inf,sizeof(best));
 57     tem[1][0]=0;       //初始化 只选一个裁判那个点 时间需要 0 
 58     for(int i=0;i<len;i++)
 59     {
 60         int o=vis[i];
 61         for(int j=0;j<n;j++)
 62         {
 63             if((1<<j)&o) best[o]=min(best[o],tem[o][j]+dis[j][0]);  //找 o状态最少时间 
 64             for(int k=0;k<n;k++)
 65             if(!((1<<k)&o)) tem[o|(1<<k)][k]=min(tem[o|(1<<k)][k],tem[o][j]+dis[j][k]); //枚举在o状态上再加一人的所有状态的最短时间 
 66         }
 67         
 68         
 69     }
 70     for(int i=0;i<(1<<n);i++)  //合并 
 71     {
 72         if(i&1)  //因为只能从 0 点出发 所以末尾必须是 1才能合并 
 73         {
 74             for(int j=i&(i-1);j;j=i&(j-1)) //枚举所有能合并成 i状态的集合 合并他们 |1 是为了保证合并的两个点都是从起点 0出发的 这个循环里的条件很神奇可以把所有能合并成i的情况分出来 
 75             {
 76                 best[i]=min(best[i],best[(i-j)|1]+best[j|1]);
 77             }
 78             
 79         }
 80         
 81     }
 82     
 83     cout<<best[(1<<n)-1]<<endl;
 84     
 85 }
 86 int main()
 87 {    
 88     ios::sync_with_stdio(false);
 89 
 90     while(cin>>n>>m)
 91     {
 92         int x[20], y[20];
 93         for(int i=0;i<n;i++)
 94         {
 95             cin>>x[i]>>y[i];
 96         }
 97         for(int i=0;i<n;i++)
 98         {
 99             cin>>val[i];
100         }
101         for(int i=0;i<n;i++)
102         {
103             for(int j=i;j<n;j++)
104             dis[i][j]=dis[j][i]=get_dis(x[i],y[i],x[j],y[j]);
105         }
106         memset(vis,0,sizeof(vis));
107         len=0;
108         for(int i=0;i<(1<<n);i++)
109         {
110             if(judge(i)) vis[len++]=i; //找能一个人解决完的所有情况 
111         }
112         int ans=DP();
113         if(ans== -1)
114         {
115             cout<<"-1 -1\n";
116             continue;
117         }
118         else cout<<ans<<" ";
119         TSP();
120     }
121         
122             
123     
124     return 0;
125 }
View Code

 

参考博客 :http://blog.csdn.net/L123012013048/article/details/48656895

转载于:https://www.cnblogs.com/qq1976648487/p/8401692.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值