《算法竞赛入门经典》之“算法设计与优化策略”

一。构造法

UVA 120 Stacks of Flapjacks

Time Limit: 3000MS     64bit IO Format: %lld & %llu

Submit Status uDebug

Description

Background

Stacks and Queues are often considered the bread and butter of data structures and find use in architecture, parsing, operating systems, and discrete event simulation. Stacks are also important in the theory of formal languages.

This problem involves both butter and sustenance in the form of pancakes rather than bread in addition to a finicky server who flips pancakes according to a unique, but complete set of rules.

The Problem

Given a stack of pancakes, you are to write a program that indicates how the stack can be sorted so that the largest pancake is on the bottom and the smallest pancake is on the top. The size of a pancake is given by the pancake‘s diameter. All pancakes in a stack have different diameters.

Sorting a stack is done by a sequence of pancake ``flips‘‘. A flip consists of inserting a spatula between two pancakes in a stack and flipping (reversing) the pancakes on the spatula (reversing the sub-stack). A flip is specified by giving the position of the pancake on the bottom of the sub-stack to be flipped (relative to the whole stack). The pancake on the bottom of the whole stack has position 1 and the pancake on the top of a stack of n pancakes has position n.

A stack is specified by giving the diameter of each pancake in the stack in the order in which the pancakes appear.

For example, consider the three stacks of pancakes below (in which pancake 8 is the top-most pancake of the left stack):

         8           7           2
         4           6           5
         6           4           8
         7           8           4
         5           5           6
         2           2           7

The stack on the left can be transformed to the stack in the middle via flip(3). The middle stack can be transformed into the right stack via the commandflip(1).

The Input

The input consists of a sequence of stacks of pancakes. Each stack will consist of between 1 and 30 pancakes and each pancake will have an integer diameter between 1 and 100. The input is terminated by end-of-file. Each stack is given as a single line of input with the top pancake on a stack appearing first on a line, the bottom pancake appearing last, and all pancakes separated by a space.

The Output

For each stack of pancakes, the output should echo the original stack on one line, followed by some sequence of flips that results in the stack of pancakes being sorted so that the largest diameter pancake is on the bottom and the smallest on top. For each stack the sequence of flips should be terminated by a 0 (indicating no more flips necessary). Once a stack is sorted, no more flips should be made.

Sample Input

1 2 3 4 5
5 4 3 2 1
5 1 2 3 4

Sample Output

1 2 3 4 5
0
5 4 3 2 1
1 0
5 1 2 3 4
1 2 0

给你一叠薄煎饼,请你写一个程序来指出要如何安排才能使这些薄煎饼由上到下依薄煎饼的半径由小到大排好。所有的薄煎饼半径均不相同。要把薄煎饼排好序需要对这些薄煎饼做翻面(flip)的动作。方法是以一抹刀插入一叠薄煎饼中,然后做翻面的动作(也就是说在抹刀上面的薄煎饼经翻 面后,会依相反的次序排列)。若一叠共有n个薄煎饼,我们定义最底下的薄煎饼的位置为1,最上面的薄煎饼位置为n。当抹刀插入位置为k时,代表从位置k到 位置n的薄煎饼要做翻面的动作。一开始时,这叠薄煎饼随意堆放,并以半径大小来表示。

大意就是按照题目所给的方法排序并输出排序的过程。

题目的排序方法就是每次可以任意选个地方然后从头开始到这个地方翻转一下,

题目中的编号是逆序的即第一个为n最后一个为1

如5 1 2 3 4

先选取第一个就是从4到开头翻转变为4 3 2 1 5然后选第二个1然后翻转下1 2 3 4 5.

类似于选择排序,每次把要排的那个数字先翻转到开头,然后选择末尾第一个未排序的翻转,这样这个元素就排好位置了。

实现过程就是每次找到当前最大的元素,如果他在排完序后的位置则不用排序,否则翻转到开头然后翻转到他排完序后的位置,因为是每次排当前最大的所以排完序后的位置我们是知道第一次在n,第二次在n-1一次类推。

 1 #include<cstring>
 2 #include<iostream>
 3 using namespace std;
 4 #include<cstdio>
 5 #define N 35
 6 #include<algorithm>
 7 int b[N],c[N];
 8 void Gb(int s,int t)
 9 {
10     if(s==t) return;
11     int mid=(s+t)>>1;
12     Gb(s,mid);
13     Gb(mid+1,t);
14     int i=s,k=s,j=mid+1;
15     while(i<=mid&&j<=t)
16     {
17         if(b[i]<=b[j])
18         {
19             c[k]=b[i];
20             i++;k++;
21         }
22         else{
23             c[k]=b[j];
24             j++;k++;
25         }
26     }
27     while(i<=mid)
28     {
29         c[k]=b[i];
30         i++;k++;
31     }
32     while(j<=t)
33     {
34         c[k]=b[j];
35         j++;k++;
36     }
37     for(i=s;i<=t;++i)
38       b[i]=c[i];
39 }
40 int main()
41 {
42     int n=0,a[N],pos[N];
43     int ans[1001]={0};
44     while(scanf("%d",&a[++n])==1)
45     {
46         b[n]=a[n];
47         while(getchar()!=‘\n‘)
48         {
49             scanf("%d",&a[++n]);
50             b[n]=a[n];
51         }
52         for(int i=1;i<=n;++i)
53           printf("%d ",a[i]);
54         printf("\n");
55         Gb(1,n);
56         for(int i=n;i>=1;--i)
57         {
58             int pos;
59             for(int j=1;j<=n;++j)
60               if(b[i]==a[j])
61               {
62                   pos=j;break;
63               }
64 /*注意找出它应该在的位置之后看看它是否已经在了,如果不是,看看它是否已经在1处了,这些就不用再移动了*/
65             if(pos==i) continue;
66             int zc[N];
67             if(pos!=1)
68             {
69                ans[++ans[0]]=n-pos+1;
70                for(int j=1;j<=pos;++j)
71                  zc[j]=a[j];
72                for(int j=1;j<=pos;++j)
73                  a[j]=zc[pos-j+1];
74                pos=1;
75             }
76             if(pos!=i)
77             {
78                 ans[++ans[0]]=n-i+1;
79             for(int j=1;j<=i;++j)
80               zc[j]=a[j];
81             for(int j=1;j<=i;++j)
82               a[j]=zc[i-j+1];
83             }
84         }
85         for(int i=1;i<=ans[0];++i)
86            printf("%d ",ans[i]);
87         memset(ans,0,sizeof(ans));
88         printf("0\n");
89         n=0;
90     }
91
92     return 0;
93 }
UVA - 1605

Building for UN

只需要设计两层就可以了,第i个国家占第一层的第i行,占第二层的每i列,这样的话就可以完全满足题目条件了。

 1 #include<cstdio>
 2 #include<iostream>
 3 using namespace std;
 4 int main()
 5 {
 6     char zmb[60];
 7     for(int i=1;i<=26*2;++i)
 8     {
 9         if(i<=26) zmb[i]=i-1+‘A‘;
10         else zmb[i]=i-27+‘a‘;
11     }
12     int n;
13     while(scanf("%d",&n)==1)
14     {
15         printf("2 %d %d\n",n,n);
16         for(int i=1;i<=n;++i)
17        {
18          for(int j=1;j<=n;++j)
19           printf("%c",zmb[i]);
20          printf("\n");
21        }
22         printf("\n");
23        for(int i=1;i<=n;++i)
24        {
25         for(int j=1;j<=n;++j)
26           printf("%c",zmb[j]);
27         printf("\n");
28        }
29      }
30     return 0;
31 }

二。中途相遇法

UVa 1152 4Values whose Sum is 0

 1 #include<iostream>
 2 using namespace std;
 3 #define N 4005
 4 #include<cstdio>
 5 #include<algorithm>
 6 typedef long long ll;
 7 int T,n,s[N*N],a[N],b[N],c[N],d[N],m=0;;
 8 ll ans=0;
 9 int read()
10 {
11     char s;
12     int ret=0,ff=1;
13     s=getchar();
14     while(s<‘0‘||s>‘9‘)
15     {
16         if(s==‘-‘) ff=-1;
17         s=getchar();
18     }
19     while(s>=‘0‘&&s<=‘9‘)
20     {
21         ret=ret*10+s-‘0‘;
22         s=getchar();
23     }
24     return ret*ff;
25 }
26 int hihiw(int x)
27 {
28     int l=1,r=m;
29     while(l<=r)
30     {
31         int mid=(l+r)>>1;
32         if(s[mid]>x) r=mid-1;
33         else l=mid+1;
34     }
35     return l;
36 }
37 int loiw(int x)
38 {
39     int l=1,r=m;
40     while(l<=r)
41     {
42         int mid=(l+r)>>1;
43         if(s[mid]>=x) r=mid-1;
44         else l=mid+1;
45     }
46     return l;
47 }
48 int main()
49 {
50     T=read();
51     while(T--)
52     {
53         n=read();m=0;
54         for(int i=1;i<=n;++i)
55         {
56             a[i]=read();b[i]=read();
57             c[i]=read();d[i]=read();
58         }
59         for(int i=1;i<=n;++i)
60           for(int j=1;j<=n;++j)
61           s[++m]=a[i]+b[j];
62         sort(s+1,s+m+1);
63     /*    for(int i=1;i<=m;++i)
64           printf("%d:%d\n",i,s[i]);*/
65         ans=0;
66         for(int i=1;i<=n;++i)
67           for(int j=1;j<=n;++j)
68           {
69               int q=-c[i]-d[j];
70             int k1=hihiw(-c[i]-d[j]);
71             int k2=loiw(-c[i]-d[j]);
72               ans+=k1-k2;
73  /*二分查找出大于该值的最小值的位置和小于等于该值的最大值的位置,二者之差就是相同的数的个数*/
74           }
75         cout<<ans<<endl;
76         if(T)cout<<endl;
77     }
78     return 0;
79 }

三.问题分解法--经典八皇后问题

四.等价转化法

UVA - 11054

Wine trading in Gergovia

 1 #include<cmath>
 2 #include<iostream>
 3 using namespace std;
 4 #include<cstdio>
 5 typedef long long ll;
 6 ll abx(ll x)
 7 {
 8     if(x<0) return -x;
 9     return x;
10 }
11 int main()
12 {
13     int n;
14     while(scanf("%d",&n)==1&&n)
15     {
16         ll ans=0;
17         ll bef=0;
18         int x;
19         for(int i=1;i<=n;++i)
20         {
21             scanf("%d",&x);
22             bef+=x;
23             ans+=abx(bef);
24         }
25         cout<<ans<<endl;
26     }
27     return 0;
28 }

五.滑动窗口法

UVA - 11572 Unique Snowflakes

 1 解法一:滑动窗口+set
 2 #define N 1000010
 3 #include<iostream>
 4 using namespace std;
 5 #include<cstdio>
 6 #include<set>
 7 #include<cstring>
 8 int T,n,a[N];
 9 int main()
10 {
11     scanf("%d",&T);
12     while(T--)
13     {
14         scanf("%d",&n);
15         for(int i=1;i<=n;++i)
16         {
17             scanf("%d",&a[i]);
18         }
19         set<int>s;
20         int L=1,R=1,ans=0;
21         while(R<=n)
22         {
23             while(R<=n&&!s.count(a[R]))
24             {
25                 s.insert(a[R]);
26                 R++;
27             }
28             ans=max(ans,R-L);
29             s.erase(a[L]);
30             L++;
31         }
32         printf("%d\n",ans);
33     }
34     return 0;
35 }
 1 /*滑动窗口+map,记录每个数上次出现的位置是哪里*/
 2 #define N 1000010
 3 #include<iostream>
 4 using namespace std;
 5 #include<cstdio>
 6 #include<map>
 7 #include<cstring>
 8 map<int,int>ma;
 9 int a[N],last[N];
10 int T,n;
11 int main()
12 {
13     scanf("%d",&T);
14     while(T--)
15     {
16         scanf("%d",&n);
17         ma.clear();
18         for(int i=1;i<=n;++i)
19         {
20             scanf("%d",&a[i]);
21             if(!ma.count(a[i]))
22             {
23                 last[i]=0;
24                 ma[a[i]]=i;
25             }
26             else {
27                 last[i]=ma[a[i]];
28                 ma[a[i]]=i;
29             }
30         }
31         int L=1,R=1,ans=0;
32         while(R<=n)
33         {
34             while(R<=n&&last[R]<L) R++;
35             ans=max(ans,R-L);
36             L++;
37         }
38         printf("%d\n",ans);
39     }
40     return 0;
41 }
时间: 2024-08-04 09:07:33

《算法竞赛入门经典》之“算法设计与优化策略”的相关文章

《算法竞赛入门经典(第二版)》pdf

下载地址:网盘下载 内容简介  · · · · · · <算法竞赛入门经典(第2版)>是一本算法竞赛的入门与提高教材,把C/C++语言.算法和解题有机地结合在一起,淡化理论,注重学习方法和实践技巧.全书内容分为12 章,包括程序设计入门.循环结构程序设计.数组和字符串.函数和递归.C++与STL入门.数据结构基础.暴力求解法.高效算法设计.动态规划初步.数学概念与方法.图论模型与算法.高级专题等内容,覆盖了算法竞赛入门和提高所需的主要知识点,并含有大量例题和习题.书中的代码规范.简洁.易懂,不

算法竞赛入门经典+挑战编程+USACO

下面给出的题目共计560道,去掉重复的也有近500题,作为ACMer Training Step1,用1年到1年半年时间完成.打牢基础,厚积薄发.   一.UVaOJ http://uva.onlinejudge.org  西班牙Valladolid大学的程序在线评测系统,是历史最悠久.最著名的OJ.   二.<算法竞赛入门经典> 刘汝佳  (UVaOJ  351道题)  以下部分内容摘自:http://sdkdacm.5d6d.com/thread-6-1-1.html   "AO

棋盘覆盖问题(算法竞赛入门经典)

在一个 2^k * 2^k 个方格组成的棋盘中,若恰有一个方格与其它方格不同,则称该方格为一特殊方格,称该棋盘为一特殊棋盘.显然特殊方格在棋盘上出现的位置有 4^k 种情形.因而对任何 k>=0 ,有 4^k 种不同的特殊棋盘.下图所示的特殊棋盘为 k=2 时 16 个特殊棋盘中的一个. 在棋盘覆盖问题中,要用下图中 4 中不同形态的 L 型骨牌覆盖一个给定的特殊棋牌上除特殊方格以外的所有方格,且任何 2 个 L 型骨牌不得重叠覆盖.易知,在任何一个 2^k * 2^k 的棋盘中,用到的 L 型

(Step1-500题)UVaOJ+算法竞赛入门经典+挑战编程+USACO

下面给出的题目共计560道,去掉重复的也有近500题,作为ACMer Training Step1,用1年到1年半年时间完成.打牢基础,厚积薄发. 一.UVaOJ http://uva.onlinejudge.org 西班牙Valladolid大学的程序在线评测系统,是历史最悠久.最著名的OJ. 二.<算法竞赛入门经典> 刘汝佳  (UVaOJ  351道题)  以下部分内容摘自:http://sdkdacm.5d6d.com/thread-6-1-1.html “AOAPC I”是刘汝佳(大

《算法竞赛入门经典第二版》 P35 习题2-4 子序列的和(subsequence)

/* <算法竞赛入门经典第二版> P35 习题2-4: 输入两个正整数 n < m < 10^6,输出 (1/n)^2 + 1/(n+1)^2 +……+ 1/m^2,保留5位小数. 输入包含多组数据,结束标志为 m=n=0. 有错欢迎指出^_^ */ #include<stdio.h> int main() { int m,n,i,j=1; while(scanf("%d%d",&m,&n) != EOF) { double sum

算法竞赛入门经典_4.3_递归

看代码 #include <stdio.h> int f(int n){ return n == 0?1:f(n-1)*n; } int main() { printf("%d\n", f(5)); return 0; } 上面f函数使用了递归,递归由两部分组成,一是递归头,二是递归体. 我们使用gcc调试工具 H:\编程书籍学习\算法竞赛入门经典2代码\算法入门经典第四章>b f 'b' 不是内部或外部命令,也不是可运行的程序 或批处理文件. H:\编程书籍学习\算

《算法竞赛入门经典》动态规划复习

codevs 4979 数塔 1 #define N 100 2 #include<iostream> 3 using namespace std; 4 #include<cstdio> 5 int a[N][N],b[N][N],n; 6 int main() 7 { 8 scanf("%d",&n); 9 for(int i=1;i<=n;++i) 10 for(int j=1;j<=i;++j) 11 { 12 scanf("

算法竞赛入门经典训练指南

最近在看算法竞赛入门经典训练指南这本书,书中不错的算法我将在博客中发布,和大家共同学习. 题目: 在你的王国里有一条n个头的恶龙,你希望雇一些骑士把它杀死(即砍掉所有头).村里有m个骑士可以雇佣,一个能力值为m的骑士可以砍掉一个直径不超过x的头,且需要支付x个金币.如何雇佣骑士才能砍掉恶龙的所有头,且需要支付的金币最少?注意,一个骑士只能砍一个头(且不能被雇佣两次). 输入格式: 输入包含多组数据.每组数据的第一行为正整数m和n(1<=m,n<=20 000):以下m行每行为一个整数,即恶龙每

算法竞赛入门经典-训练指南(10881-Piotr&#39;s Ants)

题目大意: 一根长度为L的木棍一堆蚂蚁爬,向左或向右,速度都为1,若两蚂蚁碰撞则同时转头(转身时间忽略不计),问T时间之后每只蚂蚁的位置: 输入:t,(t个样例),每个样例输入 L,T,n,接下来是n行每行两个数据,一个POS(位置),一个dir(方向): 输出:按输入顺序输出每只蚂蚁的最终位置,若处于碰撞状态则输出Turning,掉下去输出"Fell off": 解题思路: 本题类似于<挑战程序设计>的一道水题(POJ -1852  Ants),思路题:不过本题输入并不一

【算法竞赛入门经典】【第三章】课后习题(第二部分)

自从蓝桥杯之后,都没写博客了.今天将之前第三章还差的一部分习题答案补上. 3-4整数相加 这一题题目有提示,说选择合适的输入方式,即可简化问题.刚开始没想到cin,结果还用字符串来做,多亏别人提醒我一下,我才想起cin.惭愧啊.. #include <iostream> using namespace std; int main() { int a,b; char op; while(cin>>a>>op>>b){ switch(op){ case '+':