BZOJ 1003 物流运输 长歌当哭!
真是很生气啊!这道题简直整整花了我一天的时间。自己怎么这么弱呢?
算了,还是来聊一聊这道题的解题历程吧!一开始打算枚举从起点到终点的每条路径后再去动态规划。的确一开始的版本就是这样的。结果TLE了。之后打算再次版本上再去优化,曾想过把map改成数组,把深搜改成dijkstra,还打算把动态数组改成数组,由于一开始的动态规划是按照每一天推到下一天的,所以也曾把这个改成一个区间去推。但是最终在多次TLE后,我换回了WA。内心无比悲痛。无奈之下,跑去看了别人的题解,我去,这么简单。算了,真的得加把劲,多学一点。
讲一讲最终的思路吧(在别人的题解的指导下)!是这样的因为这数据实在是太小了(n<=100,m<=20,不是很小吗?)所以我们可以对于i <= n, j <= n 分别进行dijkstra,求出这段时间内的最短路,并记录在一个数组cost里面。 最后设f[i]为到第i天为止时最少费用, 则状态转移方程可表示为 f[j] = min(f[j], f[i]+cost[i+1][j]+k]) (j < i ), 最终结果是f[n]-k。
要加油啊!
启示:此题用一个sum数组来累加一个码头不能通行的天数,那么就能很快地去判断该码头在第几天是否能通行。
对解题思路的一种转换。在数据较小时,可以进行多次的最短路算法,来实现预定目标。(而不一定要一次)。
这是此题的代码
1 #include<cstdio> 2 #include<iostream> 3 #include<queue> 4 #include<cstring> 5 #define clr(i,j) memset(i,j,sizeof(i)); 6 #define rep(i,j,k) for(int i = j; i <= k; i++) 7 using namespace std; 8 9 struct edge{ 10 int to, key; 11 edge* next; 12 }; 13 14 edge edges[30000], *head[25], *pt; 15 int dis[25] = {0}, done[25] = {0}, cost[105][105] = {0}, n, m; 16 int sum[25][105] = {0}, dp[105] = {0}; 17 bool can[25][105] = {0}; 18 19 int read() 20 { 21 int s = 0, t = 1; char c = getchar(); 22 while( !isdigit(c) ){ 23 if( c == '-' ) t = -1; c = getchar(); 24 } 25 while( isdigit(c) ){ 26 s = s * 10 + c - '0'; c = getchar(); 27 } 28 return s * t; 29 } 30 31 void SPFA() 32 { 33 int f[100] = {0}; 34 rep(i,1,n){ 35 rep(j,i,n){ 36 memset(dis,127,sizeof(dis)); memset(done,0,sizeof(done)); 37 int s = 0, t = 1; f[1] = 1, dis[1] = 0, done[1] = 1; 38 while( s < t ){ 39 int now = f[++s]; 40 for(edge*l = head[now]; l; l = l->next){ 41 int to = l->to, key = l->key; 42 if( sum[to][j] - sum[to][i-1] != 0 ) continue; 43 if( dis[to] > dis[now]+key ){ 44 dis[to] = dis[now] + key; 45 if( !done[to] ) f[++t] = to, done[to] = 1; 46 } 47 } 48 done[now] = 0; 49 } 50 if( dis[m] > 10000000) { 51 cost[i][j] = dis[m]; 52 } 53 else cost[i][j] = (j-i+1)*dis[m]; 54 } 55 } 56 } 57 58 void add_edge(int x,int y,int key){ 59 pt->to = x, pt->key = key, pt->next = head[y], head[y] = pt++; 60 pt->to = y, pt->key = key, pt->next = head[x], head[x] = pt++; 61 } 62 63 int main() 64 { 65 n = read(), m = read(); 66 int k = read(), e = read(); 67 pt = edges; 68 rep(i,1,e){ 69 int x = read(), y = read(), key = read(); 70 add_edge(x,y,key); 71 } 72 int d = read(); 73 rep(j,1,d){ 74 int now = read(), x = read(), y = read(); 75 rep(i,x,y){ 76 can[now][i] = 1; 77 } 78 } 79 rep(i,1,m){ 80 rep(j,1,n){ 81 sum[i][j] = sum[i][j-1] + can[i][j]; 82 } 83 } 84 SPFA(); 85 clr(dp,60); 86 dp[0] = 0; 87 rep(i,1,n){ 88 rep(j,0,i-1){ 89 dp[i] = min(dp[i],dp[j]+cost[j+1][i]+k); 90 } 91 } 92 cout<<dp[n]-k<<endl; 93 return 0; 94 }
这是我之前的代码,如果大神知道错在哪?请多多指教:(和上面的代码比起来弱多了,上面的代码跑完此题仅28ms)
1 #include<cstdio> 2 #include<iostream> 3 #include<vector> 4 #include<cstring> 5 #include<queue> 6 #define rep(i,j,k) for(int i = j; i <= k; i++) 7 #define clr(i,j) memset(i,j,sizeof(i)) 8 #define maxn 1005 9 using namespace std; 10 11 int tot = 0, dp[105] = {0}, cost[maxn*20] = {0}, path[maxn*20] = {0}; 12 int dist[maxn*3000] = {0}; 13 int n, m, xk, e; 14 int p[maxn*3000]; 15 vector<int> day[105]; 16 17 struct node{ 18 int key, end; 19 }; 20 21 vector<node> f[105]; 22 23 int read() 24 { 25 int s = 0, t = 1; char c = getchar(); 26 while( !isdigit(c) ){ 27 if( c == '-' ) t = -1; c = getchar(); 28 } 29 while( isdigit(c) ){ 30 s = s * 10 + c - '0'; c = getchar(); 31 } 32 return s * t; 33 } 34 35 struct edge{ 36 int to, key; 37 edge* next; 38 }; 39 40 struct nod{ 41 int r, u, now; 42 bool operator < (const nod& rhs ) const{ 43 return r > rhs.r; 44 } 45 }; 46 priority_queue<nod> q; 47 48 49 edge edges[maxn], *pt, *head[maxn]; 50 51 void add_edge(int x,int y,int val) 52 { 53 pt->to = y, pt->key = val, pt->next = head[x], head[x] = pt++; 54 pt->to = x, pt->key = val, pt->next = head[y], head[y] = pt++; 55 } 56 57 void dijkstra() 58 { 59 clr(dist,127); 60 dist[2] = 0; 61 q.push((nod){0,2,1}); 62 while( !q.empty() ){ 63 nod x = q.top(); q.pop(); 64 int now = x.u; 65 if( dist[now] != x.r ) continue; 66 int k = x.now; 67 if( k == m ){ 68 int zhi = p[now]; 69 if( zhi ){ 70 if( cost[zhi] > x.r ){ 71 cost[zhi] = x.r; 72 } 73 continue; 74 } 75 p[now] = ++tot; 76 path[tot] = now; 77 cost[tot] = x.r; 78 continue; 79 } 80 for(edge*i = head[k]; i ; i = i->next) 81 { 82 int y = i->to; 83 if( now & (1<<y) ) continue; 84 int to = now|(1<<y), key = i->key; 85 if( dist[to] > dist[now] + key ){ 86 dist[to] = dist[now] + key; 87 q.push((nod){dist[to],to,y}); 88 } 89 } 90 91 } 92 } 93 94 int main() 95 { 96 n = read(), m = read(), xk = read(), e = read(); 97 pt = edges; 98 rep(i,1,e){ 99 int x = read(), y = read(), key = read(); 100 add_edge(x,y,key); 101 } 102 int k = read(); 103 rep(i,1,k){ 104 int z = read(), x = read(), y = read(); 105 rep(j,x,y){ 106 day[j].push_back(z); 107 } 108 } 109 dijkstra(); 110 int be = 0; 111 bool begin = 0; 112 rep(l,1,tot){ 113 be = 0, begin = 0; 114 rep(i,1,n){ 115 int s = day[i].size(); 116 bool ok = 1; 117 rep(j,0,s-1){ 118 if( (1<<day[i][j]) & path[l] ){ 119 if( !begin ) { 120 ok = 0; 121 break; 122 } 123 f[be-1].push_back((node){cost[l]*(i-be),i-1}); 124 ok = 0; 125 begin = 0; 126 break; 127 } 128 } 129 if( !begin && ok ){ 130 be = i; 131 begin = 1; 132 } 133 } 134 if( begin ) f[be-1].push_back((node){cost[l]*(n+1-be),n}); 135 } 136 137 clr(dp,127); 138 int s = f[0].size(); 139 rep(i,0,s-1){ 140 node x = f[0][i]; 141 int y = x.end, key = x.key; 142 dp[y] = min(dp[y],key); 143 } 144 rep(i,1,n){ 145 int s = f[i].size(); 146 rep(j,0,s-1){ 147 node x = f[i][j]; 148 int to = x.end, key = x.key; 149 dp[to] = min(dp[to],dp[i]+key+xk); 150 } 151 } 152 cout<<dp[n]<<endl; 153 return 0; 154 }
————————————————