目錄
- 神經網路(上節課作業)
- 最大子矩陣和
- 棋盤
- 亂頭髮節
- 作業
依然是拓撲,比較難
公式可能看不懂,但具體意思是:第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;
}