2024/12/7课堂记录

目录

  1. 神经网络(上节课作业)
  2. 最大子矩阵和
  3. 棋盘
  4. 乱头发节
  5. 作业

依然是拓扑,比较难

公式可能看不懂,但具体意思是:第i个点的值=∑(所有指向他的点)(这个点的值*​这条边的权)-点i的阀值

这坑以后填


填一下2024/11/23的坑,第四题,当时是半个作业

贪心/暴力的代码之前的文章有过,这里不过多说了

这次主要写dp(前缀和)的方法O(n^2*m)

 

说一下前缀和(压缩):sum[i]=a[1]+a[2]+…+a[i];

a[6]={1,1,1,1,2,4}->sum[6]={1,2,3,4,6,10}

一般的利用:(j>i)求区间和

sum[j]-sum[i]=a[i+1]+a[i+2]+…+a[j-1]+a[j]

如sum[5]-sum[2]=10-3=7

此时i=2;j=5

其实就是求a[3]+a[4]+a[5]=1+2+4=7

 

针对本题,是这样压缩:

a[][]

1  ,2  ,3  ,4

5  ,6  ,7  ,8

9  ,10,11,12

13,14,15,16

         |

        \|/

num[][]

1  ,2  ,3  ,4

6  ,8  ,10,12

15,18,21,24

28,32,36,40

利用tmp[]再次压缩:

最后每一排的一维最大连续字段和

再取所有排中最大和的最大值就行

代码没自己写,用的老师的
 //O(n^2*m)
//n行m列
#include<iostream>
#include<cstring> 
using namespace std;
int a[121][121];
int sum[121][121];
int n,m; 
int tmp[121];
int ans=0xafffffff; // 负无穷; 正无穷通常是:  0x3f3f3f3f; 
void dp()
{
	//枚举一个子矩阵的第1行i和最后1行j
    for(int i=0;i<=n;i++)         //枚举矩形的上一行 
    {
    	for(int j=i+1;j<=n;j++)   //枚举矩形的下一行  
    	{
    		memset(tmp,0,sizeof(tmp));
    		for(int k=1;k<=m;k++)
    		{
    			tmp[k]=sum[j][k]-sum[i][k];  // a[i+1][k]+a[i+2][k]....+a[j][k]
			}
			//做一维最大连续字段和
			int cur=0;//在加当前第i位之前最大字段和; 
			for(int k=1;k<=m;k++)
			{
			    cur=cur+tmp[k];
				if(cur>=ans)
				{
				    ans=cur;	
				}	
				if(cur<0)
				    cur=0;
			} 
		}
	}
} 
int main()
{
    cin>>n;  //n行m列 
    m=n;
    for(int i=1;i<=n;i++)
    {
    	for(int j=1;j<=m;j++)
    	{
    	    cin>>a[i][j];
    	    sum[i][j]=sum[i-1][j]+a[i][j]; //压缩列 
    	    //sum[i][j]:  a[1][j]+a[2][2]+a[3][j]....a[i][j]
    	    // 前i行,第j列,所有格子的和 
		}
	}
	dp();
	cout<<ans<<endl;
} 

 


一道经典dfs,注意分类讨论,再者需要剪枝,其他也就没什么了

直接看代码吧,注释都写了
 #include<iostream>
#include<cstring>
using namespace std;
int mapp[110][110],ans=0x3f3f3f3f;
int minn[110][110];
int fx[5]={0,0,-1,0,1};
int fy[5]={0,-1,0,1,0};
int m,n;
void dfs(int x,int y,int money,int color)
{
	//剪枝 
	if(money>=ans)return;       //比最终答案大 
	if(money>=minn[x][y])return; //比最短路径大 
	//到达终点 
	if(x==m&&y==m) 
	{
		ans=min(ans,money);
		minn[x][y]=ans;
//		cout<<ans;
		return;
	}
	minn[x][y]=money; 
	//开始dfs(没到达终点且是目前最短路) 
//	cout<<x<<" "<<y<<"\n";
	for(int w=1;w<=4;w++)
	{
		int xx=x+fx[w];
		int yy=y+fy[w];
		if(xx>=1&&xx<=m&&yy>=1&&yy<=m)
			if(mapp[x][y]>=0&&mapp[xx][yy]>=0)                               //脚下和眼前都有颜色 
				if(mapp[x][y]==mapp[xx][yy])dfs(xx,yy,money,mapp[xx][yy]);   	//脚下和眼前颜色相同 
				else dfs(xx,yy,money+1,mapp[xx][yy]);                        	//脚下和眼前颜色不用 
			else if(mapp[x][y]>=0&&mapp[xx][yy]<0)                          //脚下有颜色眼前没有 
				dfs(xx,yy,money+2,mapp[x][y]);									//施展魔法 
			else if(mapp[x][y]<0&&mapp[xx][yy]>=0)							//眼前有颜色脚下没有 
				dfs(xx,yy,money+((color==mapp[xx][yy])?0:1),mapp[xx][yy]);  	//脚下是魔法 
	}
	
}
int main()
{
	cin>>m>>n;
	memset(mapp,-1,sizeof(mapp));//-1代表空白 
	memset(minn,0x3f,sizeof(minn));
	while(n--)
	{
		int x,y,c;
		cin>>x>>y>>c;
		mapp[x][y]=c;
	}
	dfs(1,1,0,mapp[1][1]);
	if(ans==0x3f3f3f3f)cout<<-1;
	else cout<<ans;
}

 

单调栈

本题让求能看到多少头牛,如果暴力肯定就超时了

换种思路:有多少头牛能看见他

从左往右,挨个入栈,把所有比他小的全部踢出去(保持栈单调下降)

把所有比他小的出栈->把现在栈的长度累加->入栈

以样例一为例

10:不出栈->长度0->10入栈

3:不出栈->长度1->3入栈

7:3出栈->长度1->7入栈

4:不出栈->长度2->4入栈

12:4,7,10出栈->长度0->12入栈

2:不出栈->长度1->2入栈

最终答案:0+1+1+2+0+1=5

最后:不开longlong见祖宗

我觉得解释的挺明白的,不写注释了
 #include<iostream>
using namespace std;
int s[100010];
int top;
int main()
{
	int n;
	long long int ans=0;
	cin>>n;
	while(n--)
	{
		int h;
		cin>>h;
		for(int j=top-1;j>=0;j--)
			if(s[j]!=0&&s[j]<=h)top--;
			else break;
		ans+=top;
		s[top++]=h;
	}
	cout<<ans;
}

 

posted @   永韶  阅读(18)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示