A - Exchange
#include<bits/stdc++.h>
using namespace std;
int main()
{
int coin[10]={11,5,10,50,100,500};
int a,b,c,d,e,f,n,now;
cin>>a>>b>>c>>d>>e>>f>>n;
int pep[10];
int flag=0;
for(int i=1;i<=n;i++)
{
cin>>now;
while(now>=500&&f>0)
{
f--;
now-=500;
}
while(now>=100&&e>0)
{
e--;
now-=100;
}
while(now>=50&&d>0)
{
d--;
now-=50;
}
while(now>=10&&c>0)
{
c--;
now-=10;
}
while(now>=5&&b>0)
{
b--;
now-=5;
}
while(now>=1&&a>0)
{
a--;
now-=1;
}
if(now!=0)
{
flag=1;
break;
}
}
if(flag==1)
cout<<"No"<<endl;
else
cout<<"Yes"<<endl;
}
思路:按要求输入之后,用从大到小的货币依次尝试支付每项所需的金钱,若每次都可以让剩余金钱为0,则可以找零。
反思:刚看到这题,笔者以为这题不可以暴力求解,要用dp的知识,毕竟之前遇到过这样情况的题目:比如说有不成倍数关系的货币共两种,分别为5元和11元,可找货币数量分别为三个,一个,找零目标为15元。那么按优先选大货币的策略,会找一个11元,接着就会得到无法找零的结果,但如果直接找三个五元,就可以正确找零。
通过找规律(笔者也没找到数学证明的方法),发现只有当各个货币成整数倍关系时,才可以用本题直接求解的方法,否则要考虑dp等方法。
B - Puzzle of Lamps
#include<bits/stdc++.h>
using namespace std;
int pre=0,sum=0;
int n;
char str[40];
stack<char>qt;
int main()
{
cin>>n;
cin>>str;
int len=strlen(str);
for(int i=len;i>=1;i--)
{
if(str[i-1]=='0')
{
if(pre==0)
{
}
else
{
pre--;
sum+=pre;
pre=0;
}
}
else if(str[i-1]=='1')
{
if(pre==0)
{
pre=i;
sum+=pre;
}
else if(pre!=0)
{
pre--;
}
}
}
cout<<sum<<endl;
int pre=0,sum=0;
for(int i=len;i>=1;i--)
{
if(str[i-1]=='0')
{
if(pre==0)
{
}
else
{
pre--;
sum+=pre;
pre=0;
for(int j=1;j<=i;j++)
cout<<'B';
}
}
else if(str[i-1]=='1')
{
if(pre==0)
{
for(int j=1;j<=i;j++)
cout<<'A';
pre=i;
sum+=pre;
}
else if(pre!=0)
{
pre--;
}
}
}
}
思路:对题目样例一分析,找到了较为普世的开关灯方法,黑色表示关灯,橙色表示目标开关灯,红色表示当前开关灯:
输入:5
01100
输出:4
AAAB
第一步,一直开灯直到最右侧需要开的灯被打开为止
第二步,面对左侧亮灯区域的最右边需要关的灯,重复关灯直到需要关闭的最右侧灯也关闭为止
由此,即为AAAB,其他样例只需不断重复一二步骤直至获得目标状态为止。
代码就是在模拟这个过程(写的有点烂,为了模拟输出重复运行了一遍)
C - Routing
#include<bits/stdc++.h>
using namespace std;
char maze[510][510];
int MAX=2147483647;
int n,ans=0;
typedef struct node{
int x,y,val;
}node;
int cnt[510][510];
int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
queue<node>qu;
void spfa(char c,int x,int y)
{
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
cnt[i][j]=MAX;
cnt[y][x]=0;
node pre={x,y,0};
qu.push(pre);
while(!qu.empty())
{
node pre={qu.front().x,qu.front().y,qu.front().val};
qu.pop();
for(int i=0;i<4;i++)
{
int dx=pre.x+dir[i][1];
int dy=pre.y+dir[i][0];
int plus=1;
if(maze[dy][dx]==c||maze[dy][dx]=='P')
plus=0;
node a={dx,dy,pre.val+plus};
if(dx>=1&&dx<=n&&dy>=1&&dy<=n&&cnt[dy][dx]>a.val)
{
cnt[dy][dx]=a.val;
qu.push(a);
}
}
}
}
int main()
{
cin>>n;
for(int y=1;y<=n;y++)
for(int x=1;x<=n;x++)
cin>>maze[y][x];
spfa('R',1,1);
ans+=cnt[n][n];
spfa('B',n,1);
ans+=cnt[n][1];
cout<<ans<<endl;
}
思路:使用两次SPFA算法(笔者也是第一次写),分别从两个方向开始搜索(有点像广搜),把题目的迷宫(暂且这么叫吧)看成图,每个点都和四个方向联通,联通时通过所需的距离取决于颜色是否符合要求,如果需要改变颜色,就是距离等于一;反之,等于零。
然后开始搜索时,用队列存储,先将起点入队,然后每当起点四周有新节点的通过步数可以变小时,更新新节点的步数,并将新节点入队,起点节点出队,直到队列为空时即代表没有节点可以更新,所有节点都存储了已知可以到达的最小步数(除非有负环的情况),最后两次搜索的输出答案。