1. 程式人生 > >codeforces 8c Looking for Order

codeforces 8c Looking for Order

範圍 第一個 names 方法 output div mes ems bre

https://vjudge.net/problem/CodeForces-8C

題意:

一個平面上放著許多東西,每個東西都有一個坐標,最開始一個人在一個起始坐標,她出發去拿東西,一次要麽拿一件東西,要麽拿兩件東西,拿了之後必須返回起始坐標。

每次花費的時間是兩個坐標距離的平方,問拿完所有的東西需要的最少的時間。

思路:

由於數據範圍比較小,所以可以考慮用狀壓dp來寫。由於每次拿東西之後都要返回起點,那麽其實拿東西的順序是沒有影響的,所以利用題目給定的順序進行剪枝,即每次進行擴展的時候都考慮在前面的點已經取完了。

然後每次記錄的時候,非常巧妙的方法,如果一個點的話,直接記錄這個點,如果有兩個點的話,那麽就用(i+1)*100 + (j+1)來記錄,因為點數最多時只有24,輸出的時候遞歸輸出就行了,遞歸輸出這裏還是比較巧妙的。

代碼:(有詳細的註釋)

  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <vector>
  4 using namespace std;
  5 
  6 struct node
  7 {
  8     int x,y;
  9 } a[30];
 10 
 11 int mp[30][30];
 12 vector<int> ans;
 13 
 14 int cal(int i,int j)
 15 {
 16     return (a[i].x - a[j].x) * (a[i].x - a[j].x) + (a[i].y - a[j].y) * (a[i].y - a[j].y);
17 } 18 19 const int maxn = (1 << 24)+2; 20 const int gg = 0x3f3f3f3f; 21 22 int dp[maxn],last[maxn],rec[maxn]; 23 24 void output(int s) 25 { 26 if (~last[s]) 27 output(last[s]);//遞歸輸出 28 29 if (rec[s]) 30 { 31 if (rec[s] > 100) ans.push_back(rec[s] / 100
);//第一個擴展的點 32 33 ans.push_back(rec[s] % 100); 34 ans.push_back(0);//每次都要返回起點 35 } 36 } 37 38 int main() 39 { 40 int n; 41 42 node tmp; 43 44 scanf("%d%d",&tmp.x,&tmp.y); 45 46 scanf("%d",&n); 47 48 for (int i = 0;i < n;i++) 49 { 50 scanf("%d%d",&a[i].x,&a[i].y); 51 } 52 53 a[n] = tmp; 54 55 for (int i = 0;i <= n;i++) 56 for (int j = i + 1;j <= n;j++) 57 mp[i][j] = mp[j][i] = cal(i,j); 58 59 memset(dp,gg,sizeof(dp)); 60 memset(last,-1,sizeof(last)); 61 62 dp[0] = 0; 63 64 for (int s = 0;s < (1<<n);s++) 65 { 66 if (dp[s] >= gg) continue; 67 68 for (int i = 0;i < n;i++) 69 { 70 if (((1 << i) & s) == 0)//這個點沒有被走過 71 { 72 int val = dp[s] + mp[n][i] * 2; 73 74 if (dp[s|(1 << i)] > val) 75 { 76 dp[s|(1 << i)] = val; 77 last[s|(1 << i)] = s;//記錄前驅,下同 78 rec[s|(1 << i)] = i+1; 79 } 80 81 for (int j = i + 1;j < n;j++)//從i+1開始枚舉保證了不會有重復情況 82 { 83 if (((1<<j)&s) == 0) 84 { 85 int tmp = dp[s] + mp[n][i] + mp[i][j] + mp[j][n]; 86 87 if (dp[s|(1<<i)|(1<<j)] > tmp) 88 { 89 dp[s|(1<<i)|(1<<j)] = tmp; 90 last[s|(1<<i)|(1<<j)] = s; 91 rec[s|(1<<i)|(1<<j)] = (i+1) * 100 + (j+1);//巧妙的記錄 92 } 93 } 94 } 95 96 break;//強行順序剪枝 97 } 98 } 99 100 //printf("%d\n",dp[s]); 101 } 102 103 104 ans.clear(); 105 106 output((1<<n)-1); 107 108 printf("%d\n",dp[(1<<n)-1]); 109 110 printf("0 "); 111 112 for (int i = 0;i < ans.size();i++) 113 printf("%d%s",ans[i],i == ans.size() - 1 ? "\n" :" "); 114 115 return 0; 116 }

codeforces 8c Looking for Order