// la 3983 Robotruck // 题目大意: // // 有n个垃圾,第i个垃圾的坐标是(x,y),重量为wi,有一个机器人,要按照编号从小 // 到大的顺序捡起所有的垃圾并扔进垃圾桶(垃圾桶在原点(0,0))。机器人可以捡起几 // 个垃圾以后一起扔掉,但任何时候其手中的总重量不能超过最大载重C,两点间的距 // 离为曼哈顿距离。求机器人行走的最短距离 // // n的范围 1 <= n <= 100000, 1 <= C <= 100,保重wi小于C // // 解题思路 // // 这题一看数据的范围,解题的算法的复杂度最高只能是nlog(n)级别的复杂度。 // 想了好久。最后想到 // d(i)表示捡完前i个垃圾回到原点所行走的最短距离。 // 则状态转移方程为 // d(i) = min(d(j) + sumdist(j+1,i) + dist[j+1] + dist[i]); // 当然 j+1,j+2...i的wi的总和要小于等于C。 // // sumdist(j+1,i)表示从j+1个垃圾出发依次经过j+2,j+3...i所行走的距离 // dist[i]表示第i个垃圾到原点的距离。 // 状态转移的方程的意思明确的说就是,在前i个垃圾中找到一个j,使得d(j)加上 // 额外要走到i的距离的总和最小。(因为最坏的情况是每次只取一个垃圾,那么 // 总的路程就是横纵坐标的绝对值的和)如果能多捡1件物品,则这件物品的花费 // 就变成了它与前面一个点的距离加上它到原点的距离,而这样就节省了前面一个点 // 的距离。。。。 // // 如果这样的转移方程的话,sumdist(j+1,i),并不好求,那么我们可以先预处理 // 从原点到第i个点的所走距离之和计为sdist(i),sumdist(j+1,i) = sdist(i) - // sdist(j+1);再预处理wi的前缀和。 // 最后变成了d(i) = min(d(j) + dist[j+1] - sdist[j+1]) + sdist[i] + dist[i]; // 以优先队列的存储结构,可以在log(n)内找到满足条件的j,这样就能ac了 // // 解题感悟 // // 这道题,从5月29号卡到现在,我一遍一遍的推dp转移方程,认为自己写的实在是没 // 有任何错误,而一直wrong answer。拼命的加注释改注释,看队列里面的情况也是 // 预想的一样。。。。。。最后,费劲千辛万苦。。。发现只能按照编号顺序捡垃圾 // ,sort函数注释掉。。。ac了。。。这也是血淋淋的教训啊,感谢mw,是他说:在 // 卡题的时候,发现自己本身没有错,但一直wrong answer时,再仔仔细细的看一看 // 题目。结果调了好久才找出来,这两天有些郁闷于为什么错了,深思熟虑,也笑不 // 出来,最后ac之后,一阵狂喜,感觉突然有种神清气爽的feeling。嘿嘿,继续练吧 // 自己还水的很呢,看到书上还说了个什么单调队列优化。。。结果,完全不会。。 // 。啥时候要学学单调队列了,再抽时间补上吧,继续练吧。。。 #include <algorithm> #include <bitset> #include <cassert> #include <cctype> #include <cfloat> #include <climits> #include <cmath> #include <complex> #include <cstdio> #include <cstdlib> #include <cstring> #include <ctime> #include <deque> #include <functional> #include <iostream> #include <list> #include <map> #include <numeric> #include <queue> #include <set> #include <stack> #include <vector> #define ceil(a,b) (((a)+(b)-1)/(b)) #define endl '\n' #define gcd __gcd #define highBit(x) (1ULL<<(63-__builtin_clzll(x))) #define popCount __builtin_popcountll typedef long long ll; using namespace std; const int MOD = 1000000007; const long double PI = acos(-1.L); template<class T> inline T lcm(const T& a, const T& b) { return a/gcd(a, b)*b; } template<class T> inline T lowBit(const T& x) { return x&-x; } template<class T> inline T maximize(T& a, const T& b) { return a=a<b?b:a; } template<class T> inline T minimize(T& a, const T& b) { return a=a<b?a:b; } const int maxn = 1e5+800; struct node { int index; int w; node(){ } node(int index,int w):index(index),w(w){ } //int t; }; struct nodex{ int x; int y; int t; nodex(){ } nodex(int x,int y,int t):x(x),y(y),t(t){ } }; nodex a[maxn]; int sdist[maxn]; int dist[maxn]; int d[maxn]; int sum[maxn]; int n,p; const int inf = 0x6f6f6f6f; struct cmp{ bool operator() (node x,node y){ return x.w > y.w; } }; bool cmp2(nodex x,nodex y){ if (x.x!=y.x) return x.x < y.x; return x.y < y.x; } priority_queue<node,vector<node>,cmp> que; void init(){ scanf("%d%d",&p,&n); int x,y,t; dist[0] = 0; sum[0] = 0; for (int i=1;i<=n;i++){ scanf("%d%d%d",&x,&y,&t); a[i] = nodex(x,y,t); } // sort(a + 1 ,a + n + 1, cmp2); dist[1] = abs(a[1].x) + abs(a[1].y); sdist[1] = dist[1]; sum[1] = a[1].t; for (int i=2;i<=n;i++){ dist[i] = abs(a[i].x) + abs(a[i].y); sdist[i] = sdist[i-1] + abs(a[i].x-a[i-1].x) + abs(a[i].y-a[i-1].y); sum[i] = sum[i-1] + a[i].t; } d[1] = 2 * dist[1]; d[0] = 0; } void print(){ for (int i=1;i<=n;i++) printf("%d ",d[i]); puts(""); for (int i=1;i<=n;i++) cout << dist[i] << " "; cout << endl; for (int i=1;i<=n;i++) cout << sdist[i] << " "; cout << endl; for (int i=1;i<=n;i++) cout << sum[i] << " "; cout << endl; } void solve(){ while(!que.empty()){ que.pop(); } que.push(node(0,0)); for (int i=1;i<=n;i++){ node x; // cout << "i = " << i << endl; while(!que.empty()){ x = que.top(); // cout << "x.index = " << x.index << endl; // cout << "x.w = " << x.w << endl; if (sum[i]-sum[x.index] <= p){ break; } que.pop(); } d[i] = x.w + sdist[i] + dist[i]; //cout << "i = " << i << " d[i] " << d[i]<< " index = " << x.index << " x.w = " << x.w << endl; //cout << "fun(j) = " << d[i] - sdist[i+1] + dist[i+1] << endl; que.push(node(i,d[i] - sdist[i+1] + dist[i+1])); } //print(); // while(!que.empty()){ // node x = que.top(); // cout << "x.index = " << x.index << endl; // cout << "x.w = " << x.w << endl; // que.pop(); // } printf("%d\n",d[n]); } int main() { int t; // freopen("G:\\Code\\1.txt","r",stdin); scanf("%d",&t); int kase=1; while(t--){ init(); solve(); if (t>0) puts(""); } return 0; }
原文地址:http://blog.csdn.net/timelimite/article/details/46293201