HDU 4281 Judges' response [MTSP]

  给出N个点,第一个点是裁判,其他N-1个点需要裁判过去回答问题,每个点需要的时间不一样,而每个裁判最多能回答M分钟的问题。题目分两问,第一问是如何分配可以使使用的裁判数最少,第二问是如何分配裁判,使裁判走过的总路程和最少,裁判一开始都在1,最终也要回到1。

  至于第一问,用一个状态标记已经回答过的人,并用两个数组存回答这些人问题需要的最小裁判数以及裁判数最少时最后一个裁判的剩余时间,然后用类似哈密顿回路形式DP求解就可以了。

  第二问,是MTSP(多旅行商)问题,先求出裁判走过每个集合最终回到起点所需走的路程,然后DP合并环即可。比如1~3三个点,裁判在1,那答案就是Min(1->2->3->1,1->2->1 + 1->3->1)。

  另外,样例数据中有中文空格,真坑!

  

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <algorithm>
 4 #include <math.h>
 5 #define INF 0x3f3f3f3f
 6 #define MAXN 70000
 7 int n,m,xi[20],yi[20],ci[20];
 8 int d1[MAXN],d2[MAXN],dp[MAXN][16];
 9 int tm[MAXN],map[16][16];
10 //DP最少需要的教练数;d1和d2分别代表当前用的教练数以及最后一个教练所剩的时间
11 //每次决策选择最优的决策
12 int dpa(){
13     memset(d1,0x3f,sizeof d1);
14     int full=1<<(n-1);
15     d1[0]=d2[0]=0;
16     for(int st=0;st<full;st++){
17         for(int i=0;i<n;i++){
18             if((st>>i&1)||m<ci[i])continue;
19             int nd1=d1[st],nd2=d2[st];
20             nd2>=ci[i]?(nd2-=ci[i]):(nd1++,nd2=m-ci[i]);
21             if(nd1<d1[st|1<<i]||nd1==d1[st|1<<i]&&nd2>d2[st|1<<i])
22                 d1[st|1<<i]=nd1,d2[st|1<<i]=nd2;
23         }
24     }
25     return d1[full-1]==INF?-1:d1[full-1];
26 }
27 inline int sqr(int x){return x*x;}
28 inline int dis(int i,int j){
29     return ceil(sqrt((double)sqr(xi[i]-xi[j])+sqr(yi[i]-yi[j])));
30 }
31 //求MTSP
32 int dpb(){
33     int full=1<<n;
34     //初始化一个集合所需的时间以及距离等
35     for(int i=0;i<n;i++)
36         for(int j=0;j<n;j++)
37             map[i][j]=dis(i,j);
38     for(int i=0;i<n;i++)tm[1<<i]=ci[i];
39     for(int i=0;i<full;i++)tm[i]=tm[i&(i-1)]+tm[i&-i];
40     //TSP,为了方便直接把最后一个状态加入,最后dp[n][i]即为状态i走了一圈的值
41     memset(dp,0x3f,sizeof dp);
42     dp[0][n-1]=0;
43     for(int st=0;st<full;st++){
44         for(int i=0;i<n;i++){
45             if(dp[st][i]==INF)continue;
46             for(int j=0;j<n;j++){
47                 if((st>>j)&1)continue;
48                 if(tm[st|1<<j]<=m&&dp[st|1<<j][j]>dp[st][i]+map[i][j]){
49                     dp[st|1<<j][j]=dp[st][i]+map[i][j];
50                 }
51             }
52         }
53     }
54     //去掉高位的1来正常合并
55     for(int i=0;i<full;i++)d1[i]=dp[i^(1<<(n-1))][n-1];
56     full>>=1;
57     //区间合并,1个MTSP可能由多个TSP组成
58     for(int st=0;st<full;st++)
59         for(int x=st;x;x=st&(x-1))
60             d1[st]=std::min(d1[st],d1[x]+d1[st^x]);
61     return d1[full-1]==INF?-1:d1[full-1];
62 }
63 int main(){
64     //freopen("test.in","rb",stdin);
65     while(scanf("%d%d",&n,&m)!=EOF){
66         scanf("%d%d",&xi[n-1],&yi[n-1]);
67         for(int i=0;i<n-1;i++)scanf("%d%d",&xi[i],&yi[i]);
68         scanf("%d",&ci[n-1]);
69         for(int i=0;i<n-1;i++)scanf("%d",&ci[i]);
70         int ans=dpa();
71         if(ans==-1)printf("-1 -1\n");
72         else printf("%d %d\n",ans,dpb());
73     }
74     return 0;
75 }
posted @ 2012-09-14 10:38  Burn_E  阅读(574)  评论(0编辑  收藏  举报