大白书 1.3节 高效算法设计举例

大白书 1.3节 高效算法设计举例
例题 17 UVA 11462
简单题,注意那个数值的范围是100以内就可以了。

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <iostream>
using namespace std;
const int MAXN = 100 + 5;
int cnt[MAXN];
int main()
{
    int n;
    while(scanf("%d", &n) != EOF && n){
        memset(cnt, 0, sizeof(cnt));
        int u;
        for(int i = 1 ; i <= n ; i++){
            scanf("%d", &u);
            cnt[u]++;
        }
        int now = 1;
        int f = 1;
        while(now < MAXN){
            while(cnt[now] == 0 && now < MAXN)    now++;
            if(now == MAXN){
                printf("\n");
                break;
            }
            if(f)   f = 0;
            else    printf(" ");
            printf("%d", now);
            cnt[now]--;
        }
    }
    return 0;
}

快速IO:
#include <cstdio>
#include <cstring>
#include <cctype>

inline int readint()
{
    char c = getchar();
    while(!isdigit(c))  c = getchar();

    int x = 0;
    while(isdigit(c)){
        x = x * 10 + c - '0';
        c = getchar();
    }
    return x;
}

int buf[10];
inline void writeint(int i){
    int p = 0;
    if(i == 0)  p++;
    else while(i){
        buf[p++] = i % 10;
        i /= 10;
    }
    for(int j = p - 1 ; j >= 0 ; j--)   putchar('0' + buf[j]);
}
int main()
{
    int n, x, c[101];
    while(n = readint()){
        memset(c, 0, sizeof(c));
        for(int i = 0 ; i < n ; i++)    c[readint()]++;
        int first = 1;
        for(int i = 1 ; i <= 100 ; i++){
            for(int j = 0 ; j < c[i] ; j++){
                if(!first)  putchar(' ');
                first = 0;
                writeint(i);
            }
        }
        putchar('\n');
    }
    return 0;
}

例题 18 UVA 11078
从前向后遍历,保存之前区间的一个最大值。

#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
    int T;
    scanf("%d", &T);
    while(T--){
        int n, u;
        scanf("%d", &n);
        int mmax = -150000 * 2;
        int ans = 0;
        for(int i = 1 ; i <= n ; i++){
            scanf("%d", &u);
            if(i == 1)  mmax = u;
            else if(i == 2) ans = mmax - u, mmax = max(mmax, u);
            else    ans = max(ans, mmax - u), mmax = max(mmax, u);
        }
        printf("%d\n", ans);
    }
    return 0;
}

例题 19 UVA 11549
可以证明所有数的尾数最终都会变成0、1,、5、6中的一个,所以循环次数是优先的,直接暴力就可以。
白书介绍了一个floyd判圈法,主要节省了读取哪些数出现过的时间。

暴力法:
/* 暴力过法,注意UVA是lld就可以 */
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <map>
#include <set>
using namespace std;
#define LL long long
map<LL,LL>mm;
set<LL>s;
int buf[100];
//LL ne(LL n, LL k)
//{
//// printf("n = %I64d, k = %I64d\n", n, k);
// if(!k) return k;
// int L = 0;
// while(k){buf[L++] = k % 10, k /= 10;}
// if(n > L) n = L;
// LL ans = 0;
// for(int i = 0 ; i < n ; i++){
// ans = ans * 10 + buf[--L];
// }
//// printf("ans = %I64d\n", ans);
// return ans;
//}
int main()
{
    int T;
    scanf("%d", &T);
    while(T--){
        LL n, k;
        scanf("%lld%lld", &n, &k);
// mm.clear();
        s.clear();
        LL ans = 0;
        LL up = 1;
        for(int i = 0 ; i < n ; i++)  up *= (LL)10;
        while(!s.count(k)){
// printf("k = %I64d\n", k);
// system("pause");
// mm[k] = 1;
            s.insert(k);
            ans = max(ans, k);
            k = k * k;
            while(k >= up) k /= 10;
// k = ne(n, k * k);
        }
        printf("%lld\n", ans);
    }
    return 0;
}
Floyd判圈法:
/* 因为最后都会走成一个环,所以 */
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <string>
#include <algorithm>
#include <iostream>
#include <vector>
#include <set>
using namespace std;
#define LL long long
#define gmax(a,b) ((a) > (b) ? (a) : (b))
LL ne(LL k, LL up)
{
    while(k >= up)  k /= 10;
    return k;
}
int main()
{
    int T;
    scanf("%d", &T);
    while(T--){
        int n;
        LL k;
        scanf("%d%lld", &n, &k);
        LL k1, k2;
        LL up = 1;
        while(n--)   up *= (LL)10;
        LL ans = k;
        k1 = k;
        k2 = ne(k * k, up); ans = gmax(ans, k2);
        k2 = ne(k2 * k2, up); ans = gmax(ans, k2);
        while(k1 != k2){
            k1 = ne(k1 * k1, up);
            k2 = ne(k2 * k2, up);   ans = gmax(ans, k2);
            k2 = ne(k2 * k2, up);   ans = gmax(ans, k2);
// printf("k1 = %lld, k2 = %lld\n")
        }
        printf("%lld\n", ans);
    }
    return 0;
}

例题 20 UVA 1398
记录每个流星在矩形的区间,然后扫描法做就可以。
值得注意的是流星碰撞矩形的时间区间应该怎么去算的问题,需要自己分类讨论一下。
特别注意和矩形没有碰撞的情况、以及边界上的点不能算的问题。

/* 简单扫描法,只需要分清左事件和右事件就可以了。 关于怎么处理进入矩形的时间 分别在x方向求与左右边界相交的时间,在y方向求与上下边界相交的时间 那么,这个进入和离开值分别是这四个时间的两个中间值,具体可以用物理中速度分解来理解 注意只有当第三大的时间值大于等于0时才有解,并要求所有的合法时间大于0,详见代码注释 */
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <string>
#include <iterator>
#include <set>
using namespace std;
#define gmax(a,b) ((a) > (b) ? (a) : (b))
#define gmin(a,b) ((a) < (b) ? (a) : (b))
const int MAXN = 100000 + 5;
struct D
{
    int x, y;
    int a, b;
}d[MAXN];
struct E
{
    double t;
    int u;
    int whi;
    bool operator < (const E &rbs)const{
        if(t != rbs.t)  return t < rbs.t;
        return u < rbs.u;               ///因为球在边界也算,所以优先返回右事件
    }
    E(){}
    E(double _t, int _u, int _w){t = _t, u = _u, whi = _w;}
}e[MAXN * 2];
bool cmp(E a, E b)
{
    if(a.t == b.t)  return a.u < b.u;
    return a.t < b.t;
}
multiset<E>s;
multiset<E>::iterator it;
int w, h;
int n;
double t[10];
int main()
{
// freopen("UVA 1398.in", "r", stdin);
    int T;
    scanf("%d", &T);
    while(T--){
        scanf("%d%d%d", &w, &h, &n);
        for(int i = 0 ; i < n ; i++)    scanf("%d%d%d%d", &d[i].x, &d[i].y, &d[i].a, &d[i].b);
        s.clear();
        int cnt = 0;
        for(int i = 0 ; i < n ; i++){
            if(d[i].a == 0 && (d[i].x >= w || d[i].x <= 0))   continue;
            if(d[i].b == 0 && (d[i].y >= h || d[i].y <= 0))   continue;
            if(d[i].a > 0){
                t[1] = (double)(-1.0 * d[i].x) / (1.0 * d[i].a);        ///分别为四个边界碰撞时间
                t[2] = (double)(w - 1.0 * d[i].x) / (1.0 * d[i].a);
            }
            else if(d[i].a < 0){
                t[1] = (double)(w - 1.0 * d[i].x) / (1.0 * d[i].a);
                t[2] = (double)(-1.0 * d[i].x) / (1.0 * d[i].a);
            }
            else    t[1] = -1e9, t[2] = 1e9;

            if(d[i].b > 0){
                t[3] = (double)(-1.0 * d[i].y) / (1.0 * d[i].b);
                t[4] = (double)(h - 1.0 * d[i].y) / (1.0 * d[i].b);
            }
            else if(d[i].b < 0){
                t[3] = (double)(h - 1.0 * d[i].y) / (1.0 * d[i].b);
                t[4] = (double)(-1.0 * d[i].y) / (1.0 * d[i].b);
            }
            else    t[3] = -1e9, t[4] = 1e9;
// printf("for i = %d, t1 = %f, t2 = %f\n", i, t[2], t[3]);
            double t1 = gmax(0, gmax(t[1], t[3]));
            double t2 = gmin(t[2], t[4]);
// if(i == 6){
// printf("i = %d, t1 = %f , t2 = %f\n", i + 1, t1, t2);
// printf(" t[1] = %f, t[2] = %f, t[3] = %f, t[4] = %f\n", t[1], t[2], t[3], t[4]);
// }
            if(t2 > t1){
// e[cnt++] = E(t1, 1, i + 1);
// e[cnt++] = E(t2, 0, i + 1);
                s.insert(E(t1, 1, i + 1));  ///注意此处max
                s.insert(E(t2, 0, i + 1));
            }
        }
        int ans = 0;
// int cnt = 0;
// if(s.empty()){
// printf("0\n");
// continue;
// }
        for(it = s.begin() ; it != s.end(); it++){
            E temp = *it;
// printf("t = %f, while u = %d, cnt = %d, num = %d\n", temp.t, temp.u, cnt, temp.whi);
            if(temp.u == 0)    cnt--;
            else    cnt++;
            ans = max(ans, cnt);
            if(it == s.end())   break;
        }
// int num = 0;
// sort(e, e + cnt, cmp);
// for(int i = 0 ; i < cnt ; i++){
// if(e[i].u == 0) num--;
// else num++;
// ans = gmax(ans, num);
// }
        printf("%d\n", ans);
    }
    return 0;

例题 21 UVA 1121
很擅长的题就不说了。

/* 开两个指针,对于当前点,找到最近的一个地方即可。 因为都是正数,所以sum值随着左端点右移递减。 如果不都是正数就不存在这个做法了。 */
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <string>
using namespace std;
#define LL long long
const int MAXN = 1e5 + 5;
int a[MAXN];
int main()
{
    int n;
    while(scanf("%d", &n) != EOF){
        LL s;
        scanf("%lld", &s);
        int l = 0;
        int ans = n + 1;
        LL sum = 0;
        for(int i = 1 ; i <= n ; i++){
            scanf("%d", &a[i]);
            sum += a[i];
            int ok = 0;
            while(l < i && sum - a[l] >= s){
                ok = 1;
                sum -= a[l++];
            }
// printf("i = %d, l = %d\n", i, l);
            if(ok)  ans = min(ans, i - l + 1);
        }
        printf("%d\n", ans);
    }
    return 0;
}

~例题 22 UVA 1330
刚开始很自然的每个点找一个最优解,结果发现只能穷举的做。
题解是每个点取最高点,然后左右边界能遍历到最远处来做。这样能保证遍历到所有可能的最优子矩阵。

/* up,l,r函数分别表示向上遍历到的点、在保证取能取到的最上面的点时形成矩形的左边界和右边界 l和r数组的更新注意一下,已在代码中注释 */
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <iostream>
using namespace std;
const int MAXN = 1000 + 5;
int g[MAXN][MAXN];
char op[5];
int l[MAXN][MAXN], r[MAXN][MAXN];
int up[MAXN][MAXN];
int main()
{
    int T;
    scanf("%d", &T);
    while(T--){
        int n, m;
        scanf("%d%d", &n, &m);
        for(int i = 1 ; i <= n ; i++){
            for(int j = 1 ; j <= m ; j++){
                scanf("%s", op);
                if(op[0] == 'F')    g[i][j] = 1;
                else    g[i][j] = 0;
            }
        }
        memset(l, 0, sizeof(l));
        memset(r, 0, sizeof(r));
        memset(up, 0, sizeof(up));
        int ans = 0;
        for(int i = 1 ; i <= n ; i++){
            for(int j = 1 ; j <= m ; j++){
                if(g[i][j] == 0)    up[i][j] = 0, l[i][j] = 0;
                else    up[i][j] = up[i - 1][j] + 1, l[i][j] = l[i][j - 1] + 1;
            }
            for(int j = m ; j >= 1 ; j--){
                if(g[i][j] == 0)    r[i][j] = 0;
                else    r[i][j] = r[i][j + 1] + 1;
            }
            for(int j = 1 ; j <= m ; j++){
                if(g[i][j] == 0)    continue;
                if(i == 1)  ans = max(ans, r[i][j] + l[i][j] - 1);
                else{
                    int x = i + 1 - up[i][j];
                    int y = j;
// if(i == 2 && j == 2) printf("x = %d, y = %d\n", x, y);
                    if(up[i][j] != 1){
                        l[i][j] = min(l[i][j], l[i - 1][y]);    ///不能用max(l[i][j], l[x][y]),l[i-1][j]是已经形成的能构成大矩形的最大左边界
                        r[i][j] = min(r[i][j], r[i - 1][y]);    ///因为l[i-1][j]和l[i][j]的最小值才是确保这个矩形左右边界的存在
                    }
                    ans = max(ans, (r[i][j] + l[i][j] - 1) * up[i][j]);
                }
            }
        }
// printf("///***l\n");
// for(int i = 1 ; i <= n ; i++){
// for(int j = 1 ; j <= m ; j++) printf("%d ", l[i][j]);
// printf("\n");
// }
// printf("***///\n");
        printf("%d\n", ans * 3);
    }
    return 0;
}

~例题 23 UVA 1382
首先离散化,最粗陋的做法是O(n^4)的,即n^3的枚举,n的检测。
题解用最长连续子序列和来做,枚举上边界和下边界后,再从左往右枚举右边界,并在途中保存最优的左边界。

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <string>
#include <algorithm>
#include <iostream>
#include <map>
#include <vector>
using namespace std;
const int MAXN = 100 + 5;
struct D
{
    int x, y;
}d[MAXN];
bool cmp1(D a, D b){return a.x < b.x;}
bool cmp2(D a, D b){return a.y < b.y;}
map<int,int>mx, my;
int cntx, cnty;
int g[MAXN][MAXN];
int numx[MAXN][MAXN], numy[MAXN][MAXN];
int main()
{
//    freopen("UVA 1382.in", "r", stdin);
    int n;
    int cas = 0;
    while(scanf("%d", &n) != EOF && n){
        mx.clear();
        my.clear();
        cntx = cnty = 0;
        int u, v;
        memset(g, 0, sizeof(g));
        for(int i = 0 ; i < n ; i++)    scanf("%d%d", &d[i].x, &d[i].y);
        sort(d, d + n, cmp1);
        for(int i = 0 ; i < n ; i++)    if(mx[d[i].x] == 0) mx[d[i].x] = ++cntx;
        sort(d, d + n, cmp2);
        for(int i = 0 ; i < n ; i++)    if(my[d[i].y] == 0) my[d[i].y] = ++cnty;
        for(int i = 0 ; i < n ; i++)    g[mx[d[i].x]][my[d[i].y]]++;
        if(cntx == 1 || cnty == 1){
            printf("Case %d: %d\n", ++cas, n);
            continue;
        }
        memset(numx, 0, sizeof(numx));
        memset(numy, 0, sizeof(numy));
        for(int i = 1 ; i <= cntx ; i++){
            for(int j = 1 ; j <= cnty ; j++){
                numx[i][j] = numx[i - 1][j];
                numy[i][j] = numy[i][j - 1];
                if(g[i][j]) numx[i][j]+=g[i][j], numy[i][j]+=g[i][j];
            }
        }
//        for(int i = 1 ; i <= cntx ; i++){
//            for(int j = 1 ; j <= cnty ; j++){
//                printf("%d ", g[i][j]);
//            }
//            printf("\n");
//        }
        int ans = 0;
        for(int i = 1 ; i <= cntx; i++){
            for(int j = i + 1 ; j <= cntx; j++){
                int mmax = -1e9;
                int sum = 0;
//                int re = -1;
                for(int k = 1 ; k <= cnty; k++){
                    int up = numx[j - 1][k] - numx[i][k];
                    int divise = 0;
                    if(g[i][k - 1]) sum+=g[i][k - 1];  if(g[j][k - 1]) sum+=g[j][k - 1];
                    if(g[i][k]) divise+=g[i][k];   if(g[j][k]) divise+=g[j][k];
//                    if(i == 1 && j == 9){
//                        printf("i = %d, j = %d, k = %d, re = %d\n", i, j, k, re);
//                        printf("up = %d, sum = %d, mmax = %d\n", up, sum, mmax);
//                    }
                    ans = max(ans, sum + mmax + up + divise);
//                    if(mmax < up - sum) re = k;
                    mmax = max(mmax, up - sum);
//                    if(i == 1 && j == 2)
//                    printf("i = %d, j = %d, k = %d, ans = %d, mmax = %d, sum = %d, up = %d\n", i, j, k, ans, mmax, sum, up);
                }
            }
        }
        printf("Case %d: %d\n", ++cas, ans);
    }
    return 0;
}

例题 24 UVA 10775
枚举选的子矩阵的两个坐标,然后在第三个坐标上做最大连续子序列和。

/*
 简单的dp计数,只要把三维的转化成一维的就可以
 注意ans初始化的问题,不能直接初始化为0.
*/
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <string>
using namespace std;
#define LL long long
#define gmax(a,b) ((a) > (b) ? (a) : (b))
const int MAXN = 20 + 5;
LL g[MAXN][MAXN][MAXN];
LL sum[MAXN][MAXN][MAXN];
LL dp[MAXN];
int main()
{
 int T;
 scanf("%d", &T);
 while(T--){
 int a, b, c;
 scanf("%d%d%d", &a, &b, &c);
 LL ans = 0;
 for(int i = 1 ; i <= a ; i++){
 for(int j = 1 ; j <= b ; j++){
 for(int k = 1 ; k <= c ; k++){
 scanf("%lld", &g[i][j][k]);
 ans = min(ans, g[i][j][k]);
 }
 }
 }

 memset(sum, 0, sizeof(sum));
 for(int i = 1 ; i <= a ; i++){
 for(int j = 1 ; j <= b ; j++){
 for(int k = 1 ; k <= c ; k++){
 sum[i][j][k] = sum[i][j][k - 1] + g[i][j][k];
//                    sum[i][j][k] = sum[i][j][k - 1] + g[i][j][k] + sum[i][j - 1][k] - sum[i][j - 1][k - 1];
 }
 for(int k = 1 ; k <= c ; k++){
 sum[i][j][k] += sum[i][j - 1][k];
 }
 }

 }

 for(int x1 = 1 ; x1 <= b ; x1++){
 for(int x2 = x1 ; x2 <= b ; x2++){
 for(int y1 = 1 ; y1 <= c ; y1++){
 for(int y2 = y1 ; y2 <= c ; y2++){
 dp[0] = 0;
 for(int i = 1 ; i <= a ; i++){
 dp[i] = (sum[i][x2][y2] - sum[i][x2][y1 - 1] - sum[i][x1 - 1][y2] + sum[i][x1 - 1][y1 - 1]);
 dp[i] += gmax(0, dp[i - 1]);
 ans = gmax(ans, dp[i]);
 }
 }
 }
 }
 }

 printf("%lld\n", ans);
 if(T != 0)
 printf("\n");
 }
 return 0;
}

~例题 25 UVA 1326
每个字母出现偶数次,字母最多26种,所以自然异或和,并且用状压表示。
但是字符串数为24个刚好不能状压。
题解采取中途相遇法,即把字符串分成两部分。第一部分状压得到一些数,第二部分状压得到的在第一部分得到的数中间找有没有相等的数。

/*
    转化后就成了n个二进制表示的数,如何取最多的数使得异或和为0.
    注意题目数据没有多解。

    因为a^b == 0 -> a == b
    书上题解给出中途相遇法,即把数分成两部分,前n/2个用状压的方式求出所有能产生的异或和值
    后n/2个状压得出值去和前面比对,找出最大的一个就可以。

    写的时候写残。分成两组时123456 -> 456 123,状压表示的时候会有些麻烦导致下标错误。
*/
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
const int MAXN = 30;
int g[MAXN][MAXN];
int a[MAXN];
char op[MAXN];
struct D
{
    int u, v;
    int cnt;
}d[1 << (MAXN / 2)];
bool cmp(D a, D b)
{
    if(a.v == b.v && a.cnt == b.cnt)    return a.u < b.u;
    else if(a.v == b.v)  return a.cnt < b.cnt;
    return a.v < b.v;
}
int main()
{
//    freopen("UVA 1326.in", "r", stdin);
    int n;
    while(scanf("%d", &n) != EOF){
        memset(g, 0, sizeof(g));
        for(int i = 0 ; i < n ; i++){
            scanf("%s", op);
            for(int j = 0 ; j < (int)strlen(op) ; j++){
                g[i][op[j] - 'A'] ^= 1;
            }
            a[i] = 0;
            for(int j = 0 ; j < 26 ; j++)   a[i] = (a[i] << 1) + g[i][j];
//            printf("a[%d] = %d\n", i, a[i]);
        }
        int ans = 0, out = 0;
        int L = n / 2, R = n - n / 2;
        for(int i = 0 ; i < (1 << L) ; i++){
            d[i].u = i;
            d[i].v = 0;
            d[i].cnt = 0;
            for(int j = 0 ; j < L ; j++){
                if(i & (1 << j))    d[i].v ^= a[j], d[i].cnt++;
            }
        }
//        for(int i = 0 ; i < n ; i++)    printf("a[%d] = %d\n", i, a[i]);
//        printf("ans = %d, out = %d\n", ans, out);
        sort(d, d + (1 << L), cmp);
//        for(int i = 0 ; i < (1 << L) ; i++)
//            printf("i = %d, u = %d, v = %d, cnt = %d\n", i, d[i].u, d[i].v, d[i].cnt);
        for(int j = 0 ; j < R ; j++)    a[j] = a[j + L];
        for(int i = 0 ; i < (1 << R) ; i++){
            int v = 0;
            int cnt = 0;
            for(int j = 0 ; j < R ; j++){
                if(i & (1 << j))    v ^= a[j], cnt++;
            }
            int le = 0, re = (1 << L) - 1;
            while(le < re - 1){
                int mid = (le + re) >> 1;
                if(d[mid].v <= v)   le = mid;
                else    re = mid;
            }
            if(v == 0){
                if(ans < cnt)
                    ans = cnt, out = i;
//                else if(ans == cnt && out < i)   out = i;
            }
            int mark = -1;
            if(d[re].v == v)    mark = re;
            else if(d[le].v == v)   mark = le;
//            if(i == 6 || i == 7){
//                printf("i = %d, v = %d, cnt = %d\n", i, v, cnt);
//                printf("mark = %d, u = %d, v = %d, cnt = %d\n", mark, d[mark].u, d[mark].v, d[mark].cnt);
//            }
            if(mark == -1)  continue;
            if(d[mark].v == v){
                if(ans < d[mark].cnt + cnt)  ans = d[mark].cnt + cnt, out = ((d[mark].u << R) | i);
//                else if(ans == d[mark].cnt + cnt && out < (d[mark].u << L) | i)   out =( (d[mark].u << L )| i);
            }
//            if(i == 6){
//                printf("v = %d, cnt = %d\n", v, cnt);
//            }
        }
        if(ans == 0)    printf("0\n\n");
        else{
            printf("%d\n", ans);
            int res[MAXN];
            int cnt = 0;
            for(int i = 0 ; i < n ; i++){
                if((1 << i) & out){
                    if(i >= R)  res[cnt++] = i - R + 1;
                    else    res[cnt++] = i + L + 1;
                }
            }
            sort(res, res + cnt);
            for(int i = 0 ; i < cnt ; i++){
                printf("%d", res[i]);
                if(i == cnt - 1)    printf("\n");
                else    printf(" ");
            }
        }
    }
    return 0;
}

你可能感兴趣的:(大白书 1.3节 高效算法设计举例)