算法2的四道题

最长公共子序列

我们称序列Z = < z1, z2, ..., zk >是序列X = < x1, x2, ..., xm >的子序列当且仅当存在严格上升的序列< i1, i2, ..., ik >,使得对j = 1, 2, ... ,k, 有xij = zj。比如Z = < a, b, f, c > 是X = < a, b,c, f, b, c >的子序列。 现在给出两个序列X和Y,你的任务是找到X和Y的最大公共子序列,也就是说要找到一个最长的序列Z,使得Z既是X的子序列也是Y的子序列。

输入格式:

输入包括多组测试数据。每组数据包括一行,给出两个长度不超过200的字符串,表示两个序列。两个字符串之间由若干个空格隔开。

输出格式:

对每组输入数据,输出一行,给出两个序列的最大公共子序列的长度。

原理:a[i],b[j]为两个序列。

f[i][j]的值有四种可能

一、f[i-1][j-1] a[i]和b[j]均不是最长公共子序列中的字符

二、f[i-1][j] a[i]不是,b[j]是

如:abcd,babc 最长公共子序列明显是abc,这时f[4][4]的值其实就等于f[3][4]

三、f[i][j-1] 与二的情况相似

这三种情况就是a[i],b[j]还未比较时f[i][j]可以提前得到的初始值

注意第一种情况已经包含在了二三中,所以在代码中我们只需要比较二三种情况的最大值

四、

a[i]与b[j] 是相同的字符。

这时我们可以进行两种操作:把两个字符选入最长公共子序列中,不进行任何操作

不进行任何操作 f[i][j]依旧是f[i][j]

当选入后,f[i][j]=f[i-1][j-1]+1,因为第二种情况与第三种情况a[i]或b[j]都在最长公共子序列中,但是现在是将两个字符选入进最长公共子序列选进去,所以这两个字符比不可能在最长公共子序列中,而这个情况的最大值就是f[i-1][j-1],所以当选入后,最长公共子序列的长度会增加1,即f[i-1][j-1]+1;

所以 f[i][j]=max(f[i][j],f[i-1][j-1]+1)

代码:

#include<stdio.h>
#include<string.h>
#include<queue>
#include<algorithm>
#include<cstdio>
#include<iostream>
using namespace std;
const int N=1010;
char a[N],b[N];
int f[N][N];
int n,m;


int main()
{
    while(cin>>a+1)   //多组输入,cin>>a+1指从a[1]开始输入
    {
        cin>>b+1;
        memset(f,0,sizeof f);   //将f数组归零
        n=strlen(a+1);   //n为a字符串长度    
        m=strlen(b+1);    //m为b字符串长度
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
            {
                f[i][j]=max(f[i-1][j],f[i][j-1]);   
                if(a[i]==b[j]) f[i][j]=max(f[i][j],f[i-1][j-1]+1);
            }
        printf("%d\n",f[n][m]);
    }
}

最长上升子序列

一个数的序列bi,当b1 < b2 < ... < bS的时候,我们称这个序列是上升的。对于给定的一个序列(a1, a2, ..., aN),我们可以得到一些上升的子序列(ai1, ai2, ..., aiK),这里1 <= i1 < i2 < ... <iK <= N。比如,对于序列(1, 7, 3, 5, 9, 4, 8),有它的一些上升子序列,如(1, 7), (3, 4, 8)等等。这些子序列中最长的长度是4,比如子序列(1, 3, 5, 8)。

你的任务,就是对于给定的序列,求出最长上升子序列的长度。

输入格式:

输入有很多组,每组输入的第一行是序列的长度N (1 <= N <= 1000)。第二行给出序列中的N个整数,这些整数的取值范围都在0到10000。

输出格式:

输出每组的最长上升子序列的长度。

时间O(n^2)

f[i]表示以a[i]为结尾的最大上升子序列

如果在i之前有a[j]<a[i] 那么f[i]就可以变为max(f[i],f[j]+1)

注:初始f[i]都为1

#include<stdio.h>
#include<string.h>
#include<queue>
#include<algorithm>
#include<cstdio>
using namespace std;
const int N=1010; 
int f[N],a[N]; 
int n;
int main()
{
while(cin>>n)  //多组输入
{
	
	for(int i=1;i<=n;i++) cin>>a[i];  
	for(int i=1;i<=n;i++)
	{
	f[i]=1;                     //初始化f[i],f[i]为以w[i]为结尾的最大上升子序列
	 for(int j=1;j<i;j++)
	 {
	 	if(a[j]<a[i]) f[i]=max(f[i],f[j]+1);   
	 }
}
int res=0;
for(int i=1;i<=n;i++) res=max(res,f[i]);   //寻找最长的最大上升子序列
cout<<res<<endl;    //输出
}
}

寻找M

题目描述:

给出一个整数n,编程求出一个非零整数m,使得m是n的倍数,并且m的十进制表示中只有1和0。给出的n不大于200并且肯定存在对应的m,m是十进制数并且不大于100位。

输入:

输入包含多组测试数据。每组测试数据只有一个整数n (1 <= n <= 200)。整数0标志输入的结束。

输出:

对于每个n输出对应的整数m,m的十进制表示不多于100位。如果对于一个n存在多个合法的m,你只需输出一个即可。

下面是只能在poj上过,不能在pta上过的代码

不要使用word文档的代码会错!!!!!

原因:输出的结果会很大导致爆int,所以试了一下用long long 队列去存,但发现超时,于是用dfs去求,当深度超过19时这个数已经过大就强制跳出这条路搜其他路

#include<stdio.h>
#include<string.h>
#include<queue>
#include<algorithm>
#include<cstdio>
using namespace std;
typedef long long ll;
int n;
bool flag;
void dfs(int x,ll y)  //x为深度,y为所求答案
{
	if(x>19||flag==true) return;  //超过19层或者找到答案,跳出这条路
	if(y%n==0)         //如果y是n的倍数,输出答案
	{
		flag=true;
		printf("%lld\n",y);
		return;
	}
	dfs(x+1,y*10);   //因为所要求的数只有1和0所以只有?????0和?????1两种状态,层数要+1
	dfs(x+1,y*10+1);
}
int main()
{
	while(scanf("%d",&n),n)   //多组输入,n=0时结束
	{
	flag=false;   //将判断归0
	dfs(1,1);        //从第一层开始搜,第一个数为1

	}
}

pta能过,poj会卡的代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
void bfs(int n)
{
    queue<int> q;
    q.push(1);
    while(q.size())
    {
        int t=q.front();
        q.pop();
        if(t%n==0)
        {
            printf("%d\n",t);
            break;
        }
        q.push(t*10);
        q.push(t*10+1);
    }
}
int main()
{
    int n;
   while(scanf("%d",&n)!=EOF)
   {
       if(n==0) break;
       bfs(n);
   }
}


这是两个都能过的代码

#include<stdio.h>
#include<string.h>
#include<queue>
#include<algorithm>
#include<cstdio>
#include<iostream>
#include<vector>
#include<bitset>
using namespace std;


typedef long long ll;

int main() {
  int n;
  while (true){
    scanf("%d",&n);
    if (n == 0) break;
    for (int i = 1; ;i++) {  
      ll res=1;
     ll j=i;
    while(j!=1)
    {
    	res=res*10;
    	if(j&1) res++;
    	j>>=1;
	}
      if (res % n == 0) {
        cout << res << endl;
        break;
      }
    }
  }
}

移动桌子(Moving Tables)(1463)

来源:POJ 1083,ZOJ 1029,ACM国际大学生程序设计竞赛题解(1) P282)

问题描述:

著名的ACM(Advanced Computer Maker)公司租用了一层有400个房间的办公楼,结构如下。

ROOM

1

ROOM

3

ROOM

5

ROOM

397

ROOM

399

corrdior

ROOM

2

ROOM

4

ROOM

6

ROOM

398

ROOM

400

这层楼沿着走廊南北向的两边各有200个房间。最近,公司要做一次装修,需要在各个办公室之间搬运办公桌。由于走廊狭窄,办公桌都很大,走廊里一次只能通过一张办公桌。必须制定计划提高搬运效率。经理制定如下计划:一张办公桌从一个房间移动到另一个房间最多用十分钟。当从房间i移动一张办公桌到房间j,两个办公室之间的走廊都会被占用。所以,每10分钟内,只要不是同一段走廊,都可以在房间之间移动办公桌。为了说得更清楚一些,经理举例说明哪些情况可以同时移动,哪些情况不能同时移动。

Table Moving

Reason

Possible

(room 30 to 50) and (room 60 to 90)

No part of corridor is shared

(room 11 to 12) and (room 14 to 13)

No part of corridor is shared

Impossible

(room 20 to 40) and (room 31 to 80)

Corridor in front of room 31 to room 40 is shared

(room 1 to 4) and (room 3 to 6)

Corridor in front of room 3 is shared

(room 2 to 8) and (room 7 to 10)

Corridor in front of room 7 is shared

每个房间,只有一张办公桌进出。现在,经理想找到一种方案,使移动桌子的事情尽快完成。请编写程序解决经理的难题。

输入:

输入数据有T组测试例,在第一行给出测试例个数(T)。每个测试例的第一行是一个整数N(1≤N≤200),表示要搬运办公桌的次数。接下来N行,每行两个正整数s和t,表示一张桌子,是从房间号码s移到房间号码t。有多组输入数据,输入第一行为一个表示输入数据总数的整数N,然后是N组输入数据。

输出:

每组输入都有一行的输出数据,为一整数T,表示完成任务所花费的最少时间。

由题得上下两个房间所占用的走廊是相同的,所以可以变化i为(i-1)/2使得上下两个房间编号相同,即它们的走廊号相同,然后每个s和t就是s到t要占用一次,当所有桌子搬运完成后,遍历一次所有走廊号,它们被占用几次,就代表要单独安排几次,而最短时间,就是这些被占用次数中最大的值。

#include<stdio.h>
#include<string.h>
#include<queue>
#include<algorithm>
#include<cstdio>
#include<vector>
using namespace std;
const int N=300;
int cor[N];    //col[i]表示走廊号i被占用的次数
int n,t;
int main()
{
	scanf("%d",&t);   //多组输入
	while(t--)
	{
		memset(cor,0,sizeof cor);   //归零
		scanf("%d",&n);
		for(int i=0;i<n;i++)
		{
			int l,r;
			scanf("%d%d",&l,&r);  
			if(l>r) swap(l,r);     //因为输入中有l>r的情况,不容易循环,保证l<r 
			l=(l-1)/2;   //将l变成l所代表的走廊号
			r=(r-1)/2;    //将r变成r所代表的走廊号
			for(int j=l;j<=r;j++) cor[j]++;  //从l到r,将此段的所有被占用的走廊号+1
		}
		int ans=0;
		for(int i=0;i<210;i++) ans=max(ans,cor[i]);  //将所有的走廊号的被占用次数遍历一遍,得到最大被占用数,即为最少需要的时间
		printf("%d\n",ans*10);     //不要忘了乘10
	}
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值