2024/12/7課堂記錄

永韶發表於2024-12-07

目錄

  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;
}

  • 作業1:單調佇列

  • 作業2:發射站

相關文章