首页 > 代码库 > 《算法竞赛入门经典》之“算法设计与优化策略”

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

一。构造法

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 }

 

 

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