这里主要阐述一下贪心算法的实践 
以及一些具体的应用 
所需的头文件见 
高效算法设计(二) 
复习一下, 优先队列从小到大输出 
1 priority_queue<int, vector<int>, greater<int> > que; 
 
 
"最大值尽量小"优化 
POJ1505  
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 const int maxn = 500 + 10; int A[maxn], m, k; int last[maxn]; llong tot = 0; int maxv = -1; void init  () {     Set(A, 0);     Set(last, 0);     tot = 0;     maxv = -1; } int solve(llong x) {     llong ans = 0;     // do  not exceed x     int cnt = 1;     _for(i, 0, m) {         if (ans + A[i] <= x) ans += A[i];         else  {             ans = A[i];             cnt++;         }     }     return  cnt; } void print (llong x) {     // do  not exceed x     llong ans = 0;     int remain = k;     _forDown(i, m - 1, 0) {         if (ans + A[i] > x || i + 1 < remain) {             last[i] = 1;             remain--;             ans = A[i];         }         else  ans += A[i];     }     _for(i, 0, m-1) {         printf ("%d " , A[i]);         if (last[i]) printf ("/ " );     }     printf ("%d\n" , A[m - 1]); } int main  () {     freopen("input.txt" , "r" , stdin);     int kase;     scanf("%d" , &kase);     while (kase--) {         init();         scanf("%d%d" , &m, &k);         _for(i, 0, m) {             scanf("%d" , &A[i]);             tot += A[i];             maxv = max(maxv, A[i]);         }         // then  we finished input         // binary search         llong L = maxv, R = tot;         while (L < R) {             llong mid = L + (R - L) / 2;             if (solve(mid) <= k) R = mid;             else  L = mid + 1;         }         print (L);     } } 
 
找规律的题(无聊水题) 
UVA12627 
这个题目略显无聊  
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 llong tot(int k) {     return  k == 0 ? 1 : 3 * tot(k - 1); } llong f(int k, int i) {     if (i == 0) return  0;     if (k == 0) return  1;     int exp = (1 << (k - 1));     if (i < exp) return  2 * f(k - 1, i);     else  return  2 * tot(k - 1) + f(k - 1, i - exp); } int main  () {     freopen("input.txt" , "r" , stdin);     int T, k, a, b;     scanf("%d" , &T);     _rep(kase, 1, T) {         cin >> k >> a >> b;         cout << "Case "  << kase << ": " << f(k, b) - f(k, a - 1) << "\n";      } } 
 
模拟+贪心水题 
UVA11093 
枚举思路  
[ i , p ] [i, p] [ i , p ]   无法到 p + 1 p+1 p + 1  , 则从 [ i , i + 1 , . . . , p ] [i, i+1, ..., p] [ i , i + 1 , . . . , p ]  都无法到 p + 1 p+1 p + 1  
k ∈ [ i , i + 1 , ⋯   , p ] k \in [i, i+1, \cdots, p] k ∈ [ i , i + 1 , ⋯ , p ]  
在 k k k   这个点, 油量 ≥ 0 \geq 0 ≥ 0  , 而如果 k k k   作为起点, 油量 = 0 =0 = 0   
大于 0 0 0   都走不到,更不用说等于 0 0 0   了 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 const int maxn = 100001 + 10; int p[maxn], q[maxn]; int n; void init  () {     Set(p, 0);     Set(q, 0); } int go(int s) {     int oil = p[s] - q[s];     for (int i = (s + 1) % n; i != s; i = (i + 1) % n) {         if (oil < 0) return  i;         // i is the point cannot reached         oil += (p[i] - q[i]);     }     // s-1 to s, oil < 0, cannot reached s again     // oil >= 0, means s-1 to s, can go     if (oil < 0) return  -1;     return  s; } int solve  () {     int from = 0;     for ( ; ;) {         int to = go(from);         if (to < from) return  -1;         if (to == from) return  from;         from = to;     } } int main  () {     freopen("input.txt" , "r" , stdin);     int T;     scanf("%d" , &T);     _rep(kase, 1, T) {         init();         scanf("%d" , &n);         _for(i, 0, n) scanf("%d" , &p[i]);         _for(i, 0, n) scanf("%d" , &q[i]);         // input finished, then  solve the problem         int ans = solve();         printf ("Case %d: " , kase);         if (ans < 0) printf ("Not possible\n" );         else  printf ("Possible from station %d\n" , ans + 1);     } } 
 
位运算和贪心枚举 
LA2440  
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 const int maxm = 200000 + 10; const int maxn = 100000 + 10; int n, m; class Gate { public:     int a, b, o;     void clear  () {         a = b = o = 0;     } }; Gate gates[maxm]; void init  () {     _for(i, 0, maxm) gates[i].clear(); } // k 0s:  00...011...1 // as data flows to gates[1...m] int output(int k) {     _rep(i, 1, m) {         int a = gates[i].a;         int b = gates[i].b;         int va = a < 0 ? (-a) > k : gates[a].o;         int vb = b < 0 ? (-b) > k : gates[b].o;         gates[i].o = !(va & vb);     }     return  gates[m].o; } int solve(int vn) {     // vn are all 0     int L = 1, R = n;     while (L < R) {         int M = L + (R - L) / 2;         if (output(M) == vn) R = M;         else  L = M + 1;     }     return  L; } int main  () {     freopen("input.txt" , "r" , stdin);     int T;     scanf("%d" , &T);     while (T--) {         init();         scanf("%d%d" , &n, &m);         _rep(i, 1, m) scanf("%d%d" , &gates[i].a, &gates[i].b);         // input finished         // solve gates A = 0         int v0 = output(0);         // all 1         int vn = output(n);         // all zero         if (v0 == vn) {             _rep(i, 1, n) printf ("0" );         }         else  {             //             int x = solve(vn);             _for(i, 1, x) printf ("0" );             printf ("x" );             _rep(i, x + 1, n) printf ("1" );         }         printf ("\n" );     } } 
 
滑动窗口 
滑动窗口问题在“连续的s个元素”问题中应用非常广泛  
尽量保证滑动窗口的大小不变, 然后维护一个map<int, int> win和只出现一次的数的个数 
LA4294 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 const int maxn = 100000 + 10; int A[maxn * 3], ok[maxn * 3]; map<int, int> win; typedef map<int, int>::iterator mii; int n, s; void init  () {     Set(A, -1);     Set(ok, 0);     win.clear(); } // i is the index of A[i] bool ins(int i, map<int, int>& win) {     int first = 0;     if (!win.count(A[i])) first = true ;     win[A[i]] = win[A[i]] + 1;     return  first; } bool del(int i, map<int, int>& win) {     if (!win.count(A[i])) return  false ;     win[A[i]] = win[A[i]] - 1;     if (win[A[i]] < 1) {         win.erase(A[i]);         return  true ;     }     else  return  false ; } void slide  () {     win.clear();     int cnt = 0;     _for(i, 0, s + n + 1) {         if (cnt == s) ok[i] = true ;         if (i < s && cnt == i) ok[i] = true ;         if (i + s > s + n && cnt == s + n - i) ok[i] = true ;         if (i == s + n) break ;         if (A[i] != -1 && del(i, win)) cnt--;         if (A[i + s] != -1 && ins(i + s, win)) cnt++;     } } int main  () {     freopen("input.txt" , "r" , stdin);     int T;     cin >> T;     while  (T--) {         init();         cin >> s >> n;         _for(i, 0, n) cin >> A[s + i];         // then  solve the problem         slide();         int ans = 0;         _for(i, 0, s) {             bool valid = 1;             for (int j = i + 1; j < s + n + 1; j += s) if (!ok[j]) valid = false ;             if (valid) ans++;         }         if (ans >= n + 1) ans = s;         printf ("%d\n" , ans);     } } 
 
区间扩展并且记录上一个元素的位置 
HDU2756 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 const int maxn = 1000000 + 10; int A[maxn]; map<int, int> last; int pre[maxn]; int n; void init  () {     Set(A, 0);     Set(pre, 0);     last.clear(); } int main  () {     freopen("input.txt" , "r" , stdin);     int T;     while (scanf("%d" , &T) != EOF) {         while  (T--) {             init();             scanf("%d" , &n);             _for(i, 0, n) {                 scanf("%d" , &A[i]);                 if  (!last.count(A[i])) pre[i] = -1;                 else  pre[i] = last[A[i]];                 last[A[i]] = i;             }             int R = 0, ans = 0;             _for(L, 0, n) {                 while  (R < n && pre[R] < L) R++;                 ans = max(ans, R - L);             }             printf ("%d\n" , ans);         }     } } 
 
中途相遇法与分治思想 
LA6258 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 const int maxn = 200000 + 5; int pre[maxn], nxt[maxn], A[maxn]; map<int, int> cur; int n; void initCur  () {     cur.clear(); } void init  () {     Set(pre, 0);     Set(nxt, 0);     Set(A, 0); } inline bool uniq(int p, int L, int R) {     return  pre[p] < L && nxt[p] > R; } bool check(int L, int R) {     if (L >= R) return  true ;     for (int d = 0; L + d <= R - d; d++) {         if (uniq(L + d, L, R)) return  check(L, L + d - 1) && check(L + d + 1, R);         if (L + d == R - d) break ;         if (uniq(R - d, L, R)) return  check(L, R - d - 1) && check(R - d + 1, R);     }     return  false ; } int main  () {     freopen("input.txt" , "r" , stdin);     int T;     scanf("%d" , &T);     while  (T--) {         // init();         initCur();         scanf("%d" , &n);         _for(i, 0, n) {             scanf("%d" , &A[i]);             if (!cur.count(A[i])) pre[i] = -1;             else  pre[i] = cur[A[i]];             cur[A[i]] = i;         }         initCur();         _forDown(i, n - 1, 0) {             if (!cur.count(A[i])) nxt[i] = n;             else  nxt[i] = cur[A[i]];             cur[A[i]] = i;         }         if (check(0, n - 1)) printf ("non-boring\n" );         else  printf ("boring\n" );     } } 
 
贪心和博弈 
LA6271  
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 const int maxn = 1024 + 5; char G[maxn][maxn]; int n; // vector<int> win, gray point; vector<int> lose, black point void solve  () {     vector<int> win, lose;     _rep(i, 2, n) {         if (G[1][i] == '1' ) win.push_back(i);         else  lose.push_back(i);     }     int rnd = n;     while  (rnd > 1) {         vector<int> win2, lose2, last;         // phase 1         _for(i, 0, lose.size()) {             int _lose = lose[i];             bool matched = false ;             _for(j, 0, win.size()) {                 int& _win = win[j];                 if (_win > 0 && G[_win][_lose] == '1' ) {                     printf ("%d %d\n" , _win, _lose);                     win2.push_back(_win);                     _win = 0;                     matched = true ;                     break ;                 }             }             if (!matched) last.push_back(_lose);         }         // phase 2         bool first = true ;         _for(i, 0, win.size()) {             int _win = win[i];             if (_win > 0) {                 if (first) {                     printf ("1 %d\n" , _win);                     first = false ;                 }                 else  last.push_back(_win);             }         }         // phase 3         for (int i = 0; i < last.size(); i += 2) {             printf ("%d %d\n" , last[i], last[i + 1]);             int keep = last[i];             if (G[last[i + 1]][keep] == '1' ) keep = last[i + 1];             if (G[1][keep] == '1' ) win2.push_back(keep);             else  lose2.push_back(keep);         }         win = win2;         lose = lose2;         rnd >>= 1;     } } int main  () {     freopen("input.txt" , "r" , stdin);     while (scanf("%d" , &n) == 1) {         _rep(i, 1, n) scanf("%s" , G[i] + 1);         // input finished         solve();     } } 
 
扫描法水题 
LA4621 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 const int maxn = 1000000 + 10; int n, p[maxn], s[maxn], h[maxn]; int main  () {     freopen("input.txt" , "r" , stdin);     int kase;     scanf("%d" , &kase);     while  (kase--) {         scanf("%d" , &n);         _for(i, 0, n) scanf("%d" , &p[i]);         _for(i, 0, n) scanf("%d" , &s[i]);         int ans = 0;         int level = s[0];         _for(i, 0, n) {             if (level < p[i]) level = p[i];             if (level > s[i]) level = s[i];             h[i] = level;         }         level = s[n - 1];         _forDown(i, n - 1, 0) {             if (level < p[i]) level = p[i];             if (level > s[i]) level = s[i];             ans += min(level, h[i]) - p[i];         }         printf ("%d\n" , ans);     } } 
 
单调栈和状态组织 
LA4950 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 const int maxn = 1000 + 10; char grid[maxn][maxn]; int height[maxn], ans[maxn * 2]; int n, m; class Rec { public:     int c, h;     Rec(int _c = 0, int _h = 0) : c(_c), h(_h) {} }; Rec stk[maxn]; void init  () {     Set(height, 0);     Set(ans, 0); } int main  () {     freopen("input.txt" , "r" , stdin);     int kase;     scanf("%d" , &kase);     while  (kase--) {         init();         scanf("%d%d" , &n, &m);         _for(i, 0, n) scanf("%s" , grid[i]);         _for(i, 0, n) {             int top = -1;             _for(j, 0, m) {                 if (grid[i][j] == '#' ) {                     top = -1;                     height[j] = 0;                 }                 else  {                     // land can be sold                     height[j]++;                     Rec cur(j, height[j]);                     if (top < 0) stk[++top] = cur;                     else  {                         while (top >= 0 && stk[top].h >= cur.h) cur.c = stk[top--].c;                         if (top < 0 || stk[top].h - stk[top].c < cur.h - cur.c) stk[++top] = cur;                     }                     ans[j - stk[top].c + stk[top].h + 1]++;                 }             }         }         _rep(i, 1, n + m) if (ans[i]) printf ("%d x %d\n" , ans[i], i * 2);     } }