记录week12的实验三道题+作业五道题

sverer
作业:
A:
在这里插入图片描述
这道题很简单,不在赘述
代码:

#include <iostream>
using namespace std;
int main()
{
    int n,i,m,t,ans;
    while(cin>>n)
    {
        int a[32768]= {0};
        t=(n+1)/2;
        for(i=0; i<n; i++)
        {
            cin>>m;
            a[m]++;
            if(a[m]>=t)
                ans=m;
        }
        cout<<ans<<endl;;
    }
    return 0;
}

B:三维迷宫
在这里插入图片描述
这道题和二维迷宫类似,不过换成了三维,都是使用BFS搜索。做过二维迷宫应该比较容易入手。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <queue>
using namespace std;
#define Max 50
bool maze[Max][Max][Max];
bool flag[Max][Max][Max];
int dir,h,w;
typedef struct Node{
	int x;
	int y;
	int dir;
	int deep;
}node;
int sx,sy,sdir,ex,ey,edir;
int Count;
bool bfs(){
	queue<node> Que;
	node point;
	point.x=sx;
	point.y=sy;
	point.dir=sdir;
	point.deep=0;
    Que.push(point);
	flag[sdir][sx][sy]=1;
	int x,y,bdir,bdeep;
	while(!Que.empty()){
		point=Que.front();
	    Que.pop();
		x=point.x,y=point.y;
		bdir=point.dir,bdeep=point.deep;
		if(x==ex && y==ey && bdir==edir){
			Count=bdeep;
			return true;
		}
		if(y-1>=1 && maze[bdir][x][y-1] && !flag[bdir][x][y-1]){
			point.x=x;
			point.y=y-1;
			point.dir=bdir;
			point.deep=bdeep+1;
			flag[bdir][x][y-1]=1;
			Que.push(point);
		}
		if(y+1<=w && maze[bdir][x][y+1] && !flag[bdir][x][y+1]){
			point.x=x;
			point.y=y+1;
			point.dir=bdir;
			point.deep=bdeep+1;
			flag[bdir][x][y+1]=1;
			Que.push(point);
		}
		if(x-1>=1 && maze[bdir][x-1][y] && !flag[bdir][x-1][y]){
			point.x=x-1;
			point.y=y;
			point.dir=bdir;
			point.deep=bdeep+1;
			flag[bdir][x-1][y]=1;
			Que.push(point);
		}
	    if(x+1<=h && maze[bdir][x+1][y] && !flag[bdir][x+1][y]){
			point.x=x+1;
			point.y=y;
			point.dir=bdir;
			point.deep=bdeep+1;
			flag[bdir][x+1][y]=1;
			Que.push(point);
		}
		if(bdir-1>=1 && maze[bdir-1][x][y] && !flag[bdir-1][x][y]){
			point.x=x;
			point.y=y;
			point.dir=bdir-1;
			point.deep=bdeep+1;
			flag[bdir-1][x][y]=1;
			Que.push(point);
		}
		if(bdir+1<=dir && maze[bdir+1][x][y] && !flag[bdir+1][x][y]){
			point.x=x;
			point.y=y;
			point.dir=bdir+1;
			point.deep=bdeep+1;
			flag[bdir+1][x][y]=1;
			Que.push(point);
		}
	}
	return false;
}
 
int main(){
	while(scanf("%d%d%d",&dir,&h,&w),dir){
		memset(maze,0,sizeof(maze));
		memset(flag,0,sizeof(flag));
		char str;
	    for(int i=1;i<=dir;i++){
			getchar();
			for(int j=1;j<=h;j++){
				for(int k=1;k<=w;k++){
					str=getchar();
					if(str=='.')
						maze[i][j][k]=1;
					else if(str=='S'){
					    sdir=i;
						sx=j;
						sy=k;
						maze[i][j][k]=1;
					}
					else if(str=='E'){
						edir=i;
						ex=j;
						ey=k;
						maze[i][j][k]=1;
					}
				}
				getchar();
			}
		}
		if(bfs())
			printf("Escaped in %d minute(s).\n",Count);
		else
			printf("Trapped!\n");
	}
	return 0;
}

C:最大和连续子序列增强版
在这里插入图片描述
这是个最大和连续子序列问题的增强版,区别在于这道题有多个区间,一是我们要增加一维表示区间数目。用DP[i][j]表示前j个数分为i段能获得的最大和。状态转移方程为

dp[ i ][ j ]=max( dp[ i ][ j-1 ]+a[ j ] , max( dp[ i-1 ][ k ] )+a[ j ] ) i-1<=k<=j-1

这个方程的含义是:将第 aj 个数算在第 i 段的最后还是 第i段的开始。也就是aj和前面的一起在第 i 段还是 前面最多在第i-1段 aj在第i段。
如果是前者:dp[ i ][ j ] = dp[ i ][ j-1 ]+a[ j ]
如果是后者:dp[ i ][ j ] = max( dp[ i-1 ][ k ] )+a[ j ] 1<=k<=j-1
后者中 dp[ i-1 ][ k ]指的是,由于其区间不连续,则i-1段最后一个数可以是 1<=k<=j-1种的任何一个。取最大值即可。

然后这道题还要进行空间和时间上的优化,这里是用了滚动数组和记忆化。
用dp[j]表示表示到第j个的时候的最大和,解决空间的问题。用pre[ j-1 ]表示max( dp[ i-1 ][ k ] )以免再次遍历K ,解决了时间复杂度的问题。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>//HDU 1024
using namespace std;
 
const int maxn = 1e6;
const int inf = 0x3f3f3f3f;
 
long long dp[maxn + 5];
long long a[maxn +5];
long long pre[maxn + 5];
int n, m;
 
int main(){
	while(~scanf("%d %d", &m, &n)){	
		memset(dp, 0, sizeof(dp));
		memset(pre, 0, sizeof(pre));
		for(int i = 1; i <= n; i++){
			scanf(" %lld", &a[i]);
		}
		long long tmp;

		for(int i = 1; i <= m; i++){
			tmp = -inf;
			for(int j = i; j <= n; j++){
				dp[j] = max(dp[j - 1], pre[j - 1]) + a[j];
				pre[j - 1] = tmp;
				tmp = max(tmp, dp[j]);
			}
		}
		printf("%lld\n", tmp);
	}
	return 0;
}

D:区间DP
在这里插入图片描述
这道题是括号匹配,套用区间DP的板子 ,本质是依次递推 ,最外层枚举 区间长度 ,内一层枚举 起点位置 ,最内层枚举 分割点位置。
状态方程:如果匹配 dp[i][j]=dp[i+1][j-1]+2;
然后枚举dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]);。

#include<iostream>
#include<cstring>
#include<algorithm>//POJ 2955
using namespace std;
int dp[105][105];
string s;
bool match(char c1,char c2)
{
	if(c1=='('&&c2==')') return true;
	if(c1=='['&&c2==']') return true;
	else return false;
}
void solve()
{
	memset(dp,0,sizeof(dp));
	int l=s.length();
	for(int d=1;d<l;d++)
	{
		for(int i=0;i+d<l;i++)
		{
			int j=i+d;
			if(match(s[i],s[j])) 
			{
				dp[i][j]=dp[i+1][j-1]+2;
			}
			for(int k=i;k<=j-1;k++)
			dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]);
		}
	}
}
int main()
{
	while(1) 
	{
	    cin>>s;
		if(s[0]=='e') break;
		solve();
		cout<<dp[0][s.length()-1]<<endl;; 
	}
	return 0;
} 

E:状压DP
在这里插入图片描述
将15个作业压缩成一个数,每一位二进制代表一门课是否完成。然后开始DP。
枚举从1到bit(1<<n)的每一个状态i;
然后枚举每一门课j(倒叙枚举,因为输入是按照字典序递增输入的),检查状态i是否完成了第j门课通过与运算,如果完成了第j门课,计算不完成第j门课时所扣的分加上完成第j门课所扣的分是否比当前状态i所扣的分少,如果少于则进行更新分数和时间,并记下j作为路径输出。

#include <iostream>
#include <cstdio>
const int inf=0x3f3f3f3f;
const int MAX=(1<<15)+10;
using namespace std;
int n,dp[MAX],t[MAX],pre[MAX],ddl[20],len[20];
char s[20][110];
 
void output(int x)
{
	if(!x)return;
	output(x-(1<<pre[x]));
	printf("%s\n",s[pre[x]]);
}
 
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d",&n);
		for(int i=0;i<n;i++)
			scanf("%s%d%d",s[i],&ddl[i],&len[i]);
		int bit=1<<n;
		
		for (int i=1;i<bit;i++)
		{
			dp[i]=inf;
			for (int j=n-1;j>=0;j--)
			{
				int temp=1<<j;
				if (!(i&temp))
					continue;
				//扣分:   上一个状态的时间+长度-截止时间
				int score=t[i-temp]+len[j]-ddl[j];
				if (score<0)
					score=0;
				if (dp[i]>dp[i-temp]+score)
				{
					dp[i]=dp[i-temp]+score;
					t[i]=t[i-temp]+len[j];
					pre[i]=j;
				}
			}
		}
		printf("%d\n",dp[bit-1]);
		output(bit-1);
	}
	return 0;
}

实验题:
实验题第一道很简单就不说了,第二题是矩阵旋转,还是方阵,跟上上周的魔方一样,可以用多次旋转90度取代旋转180度和270度即可。
第三题是一道字符串的题,但是直接去做很难。它看起来是回文字符串,但是基本跟回文字符串不搭边。
我们从反方向入手,把总的方案数求出来,可由排列组合直到总方案数是n*(n-1)/2,然后求除不符合规则的字符串数目。
由题干可知,不符合规则的字符串只有两种类型,xxxy 和 xyyy。其他的均符合要求。所以我们只需要求除xxxy和xyyyy这两种数目即可,我们可以正序遍历一边然后倒叙遍历一遍。还有要注意要把xy去重,因为正着算了一遍,倒叙的时候又算了一遍。

#include<iostream>
using namespace std;
long long int n;
long long int ans;
long long int  lenth=1;
string s;
int main()
{  
    cin>>n; cin>>s;
    ans=n*(n-1)/2;
    for(int i=1;i<n;i++)//AAAAB  
    {
        if(s[i]==s[i-1]) 
		   lenth++;
        else
		{
		    ans=ans-lenth;
			lenth=1;
        }
	}
    lenth=1;
    for(int i=n-2;i>=0;i--)
    {
        if(s[i]==s[i+1]) 
		   lenth++;
        else
		{
		    ans=ans-lenth;
			lenth=1;
        }
    }
    for(int i=1;i<n;i++)
	   if(s[i]!=s[i-1])
          ans++;
 
	cout<<ans<<endl;
    return 0;
}

另外附上AB题的代码:

A:
#include<iostream>
using namespace std;
int last=0x3f3f3f3f;
int main (){
int n;cin>>n;
int p=0;int ans=0;
for(int i=0;i<n;i++)
{
	cin>>p;
	if(p!=last)
	{
		ans++;last=p;
	}
	else continue;
}
cout<<ans<<endl;

return 0;
}
B:
#include<iostream>
using namespace std;
#define maxn 32
#define maxm 32
int n,m;
int G[maxn][maxm];
int mark[maxn][maxm];

int main (){
cin>>n>>m;
for(int i=0;i<n;i++)
{
   for(int j=0;j<m;j++)
   {
     cin>>G[i][j];   	
   } 
}
for(int i=0;i<n;i++)
{
	for(int j=0;j<m;j++)
	{
		if(j-1>=0&&j+1<=m-1)
		{
		  if(G[i][j-1]==G[i][j]&&G[i][j]==G[i][j+1])
		  {
		     mark[i][j-1]=-1;mark[i][j]=-1;mark[i][j+1]=-1;	
		  }	
		}
	}
}
for(int j=0;j<m;j++)
{
	for(int i=0;i<n;i++)
	{
		if(i>=1&&i<=n-2)
		{
		  if(G[i-1][j]==G[i][j]&&G[i][j]==G[i+1][j])
		  {
		     mark[i-1][j]=-1;mark[i][j]=-1;mark[i+1][j]=-1;	
		  }	
		}
	}
}
for(int i=0;i<n;i++)
{
   for(int j=0;j<m;j++)
   {
   	if(mark[i][j]!=-1)
   	cout<<G[i][j];
   	else
   	cout<<0;
   	if(j<m-1)cout<<" ";
   }
  if(i<n-1) cout<<endl;
}

return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值