题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4281
题意:给出N个点,第一个点是裁判,其他N-1个点需要裁判过去回答问题,每个点需要的时间不一样,而每个裁判最多能回答M分钟的问题。题目分两问,第一问是如何分配可以使使用的裁判数最少,第二问是如何分配裁判,使裁判走过的总路程和最少,裁判一开始都在1,最终也要回到1。
思路:首先我们可以把符合条件的集合预处理出来,然后对于第一问,可以用状态压缩解决,dp[state]表示该状态下的最少裁判数,对于第二问,就是多旅行商问题了,dp[i][j]表示状态为i,在位置j的最小花费,然后开一个best数组来保存最有状态,最后枚举子集,DP合并环即可。比如1~3三个点,裁判在1,那答案就是Min(1->2->3->1,1->2->1 + 1->3->1)。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 #define inf 1<<30 8 9 struct Point{ 10 int x,y; 11 }point[17]; 12 13 int n,m,ans,val[17],dp1[1<<17]; 14 int dp[1<<17][17],best[1<<17]; 15 int Ok[1<<17]; 16 int dist[17][17]; 17 18 int Get_Dist(int i,int j) 19 { 20 return ceil(sqrt(double(point[i].x-point[j].x)*(point[i].x-point[j].x)+double(point[i].y-point[j].y)*(point[i].y-point[j].y))); 21 } 22 23 int Judge(int state) 24 { 25 int sum=0; 26 for(int i=0;i<n;i++){ 27 if(state&(1<<i))sum+=val[i]; 28 } 29 return sum<=m; 30 } 31 32 int Solve() 33 { 34 fill(dp1,dp1+(1<<n),inf); 35 dp1[0]=0; 36 for(int state=0;state<(1<<n);state++){ 37 if(Ok[state]){ 38 for(int i=0;i<(1<<n);i++){ 39 if((state&i)==0&&dp1[i]!=inf){ 40 dp1[state|i]=min(dp1[state|i],dp1[i]+1); 41 } 42 } 43 } 44 } 45 return dp1[(1<<n)-1]; 46 } 47 48 int TSP() 49 { 50 fill(best,best+(1<<n),inf); 51 for(int i=0;i<(1<<n);i++) 52 for(int j=0;j<n;j++)dp[i][j]=inf; 53 dp[1][0]=0; 54 for(int state=0;state<(1<<n);state++){ 55 if(Ok[state]){ 56 for(int i=0;i<n;i++)if(state&(1<<i)){ 57 if(dp[state][i]==inf)continue; 58 best[state]=min(best[state],dp[state][i]+dist[i][0]); 59 for(int j=0;j<n;j++)if(!(state&(1<<j))){ 60 dp[state|(1<<j)][j]=min(dp[state|(1<<j)][j],dp[state][i]+dist[i][j]); 61 } 62 } 63 } 64 } 65 for(int state=0;state<(1<<n);state++){ 66 if(state&1){ 67 for(int substate=state&(state-1);substate;substate=state&(substate-1)){ 68 best[state]=min(best[state],best[substate]+best[(state^substate)|1]); 69 } 70 } 71 } 72 return best[(1<<n)-1]; 73 } 74 75 76 int main() 77 { 78 while(~scanf("%d%d",&n,&m)){ 79 for(int i=0;i<n;i++)scanf("%d%d",&point[i].x,&point[i].y); 80 for(int i=0;i<n;i++)scanf("%d",&val[i]); 81 for(int i=0;i<n;i++) 82 for(int j=0;j<n;j++)dist[i][j]=Get_Dist(i,j); 83 for(int s=0;s<(1<<n);s++){ 84 Ok[s]=Judge(s); 85 } 86 ans=Solve(); 87 if(ans==inf){ 88 puts("-1 -1"); 89 continue; 90 } 91 printf("%d %d\n",ans,TSP()); 92 } 93 return 0; 94 }