本质是bfs求最短路,通常我们的状态是一个点,现在我们的状态是01数组,我们可以将它转换成十进制来简便的表示状态,但是状态转移时要熟悉位运算。
cpp
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int arr[101][11];
int n,m,step[1025];
queue<int>q;
bool wei(int x,int y){
x >>= y;
return x&1;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
for(int j=0;j<n;j++)
cin>>arr[i][j];
q.push((1<<n)-1);//全开
step[(1<<n)-1] = 1;
while(!q.empty()){
int now = q.front();
q.pop();
if(now == 0){
cout<<step[0]-1;
return 0;
}
for(int i=1;i<=m;i++){
int temp =now;
for(int j=0;j<n;j++){
if(arr[i][j] == 1 && wei(temp,j)) temp ^= (1<<j);
else if(arr[i][j] == -1 && !wei(temp,j)) temp |= (1<<j);
}
if(step[temp] == 0){
step[temp] = step[now] + 1;
q.push(temp);
}
}
}
cout<<-1;
return 0;
}
简单的部分背包
cpp
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll dp[205],n,m,a,b;
int main()
{
cin>>n>>m;
memset(dp,0x3f,sizeof(dp));
dp[0]=0;
while(m--){
cin>>a>>b;
for(int i=n;i>=1;i--){
for(int j=0;j<=i;j++){
dp[i]=min(dp[i],dp[i-j]+a*(ll)pow(j,b));
}
}
}
cout<<dp[n];
return 0;
}
P1474 [USACO2.3] Money System / [USACO07OCT]Cow Cash G - 洛谷
简单的完全背包求方案数
cpp
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll n,v,dp[10005],a;
int main()
{
cin>>v>>n;
dp[0]=1;
while(v--){
cin>>a;
for(int i=a;i<=n;i++) dp[i]+=dp[i-a];
}
cout<<dp[n];
return 0;
}
简单的01背包求方案数
cpp
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll n,m,dp[10005],a,mod=1000007;
int main()
{
cin>>n>>m;
dp[0]=1;
while(n--){
cin>>a;
for(int i=m;i>=0;i--){
for(int j=1;j<=min(i,(int)a);j++){
dp[i]+=dp[i-j];
dp[i]%=mod;
}
}
}
cout<<dp[m];
return 0;
}
这题有个优化小技巧,记录哪个点是在哪个时间访问的,再通过这个时间去映射到块的大小。
cpp
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n,m,ans[1005][1005],v[100005],sum,a,b,now=1;
char arr[1005][1005];
int dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};
void bfs(int sx,int sy,int num){
sum=1;
queue<pair<int,int> >r;
r.push(make_pair(sx,sy));
ans[sx][sy]=num;
while(!r.empty()){
int x = r.front().first,y = r.front().second;
r.pop();
for(int i=0;i<4;i++){
if(x+dx[i]>=1&&x+dx[i]<=n&&y+dy[i]>=1&&y+dy[i]<=n){
if(arr[x][y]!=arr[x+dx[i]][y+dy[i]]&&ans[x+dx[i]][y+dy[i]]==0){
ans[x+dx[i]][y+dy[i]]=num;
sum++;
r.push(make_pair(x+dx[i],y+dy[i]));
}
}
}
}
v[num]=sum;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
cin>>arr[i][j];
while(m--){
cin>>a>>b;
if(ans[a][b]) cout<<v[ans[a][b]]<<endl;
else{
bfs(a,b,now++);
cout<<v[ans[a][b]]<<endl;
}
}
return 0;
}
P8673 [蓝桥杯 2018 国 C] 迷宫与陷阱 - 洛谷
广搜,注意记录该点是否访问是要记录该点的坐标和剩余无敌的步数。
cpp
#include<bits/stdc++.h>
#define ll long long
using namespace std;
struct point{
int x,y,t,step;//无敌时间
};
int n,k,dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};
char arr[1005][1005];
bool vis[1005][1005][11];//第三维是时间
int main()
{
cin>>n>>k;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
cin>>arr[i][j];
queue<point>r;
r.push(point{1,1,0,0});
while(!r.empty()){
int x=r.front().x,y=r.front().y,t=r.front().t,s=r.front().step;
if(x==n&&y==n){
cout<<s;
return 0;
}
r.pop();
for(int i=0;i<4;i++){
if(x+dx[i]>=1&&x+dx[i]<=n&&y+dy[i]>=1&&y+dy[i]<=n){
if(arr[x+dx[i]][y+dy[i]]=='.'||(arr[x+dx[i]][y+dy[i]]=='X'&&t>0)){
if(!vis[x+dx[i]][y+dy[i]][max(t-1,0)]){
r.push(point{x+dx[i],y+dy[i],max(t-1,0),s+1});
vis[x+dx[i]][y+dy[i]][max(t-1,0)]=true;
}
}
if(arr[x+dx[i]][y+dy[i]]=='%'){
arr[x+dx[i]][y+dy[i]]='.';
r.push(point{x+dx[i],y+dy[i],k,s+1});
vis[x+dx[i]][y+dy[i]][k]=true;
}
}
}
}
cout<<-1;
return 0;
}
P12323 [蓝桥杯 2023 省 Java B] 阶乘求和 - 洛谷
注意该题只取后9位,当i>=40时,40!,41!后9位都是0,所以只用循环到39.
cpp
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll ans=0,now=1,mod=1000000000;
int main()
{
for(ll i =1;i<=40;i++){
// now *= (i%mod);
now *= i;
now %= mod;
ans += now;
ans %= mod;
}
cout<<ans;
return 0;
}