P1190 [NOIP2010 普及组] 接水问题
题目描述
学校里有一个水房,水房里一共装有 m 个龙头可供同学们打开水,每个龙头每秒钟的供水量相等,均为 11。
现在有 n 名同学准备接水,他们的初始接水顺序已经确定。将这些同学按接水顺序从 11 到 n 编号,i 号同学的接水量为 wi。接水开始时,1 到 m 号同学各占一个水龙头,并同时打开水龙头接水。当其中某名同学 j 完成其接水量要求 wj 后,下一名排队等候接水的同学 k 马上接替 j 同学的位置开始接水。这个换人的过程是瞬间完成的,且没有任何水的浪费。即 j 同学第 x 秒结束时完成接水,则 k 同学第 x+1 秒立刻开始接水。若当前接水人数 ′n′ 不足 m,则只有 ′n′ 个龙头供水,其它 ′m−n′ 个龙头关闭。
现在给出 n 名同学的接水量,按照上述接水规则,问所有同学都接完水需要多少秒。
输入格式
第一行两个整数 n 和 m,用一个空格隔开,分别表示接水人数和龙头个数。
第二行 n 个整数 w1,w2,…,wn,每两个整数之间用一个空格隔开,wi 表示 i 号同学的接水量。
输出格式
一个整数,表示接水所需的总时间。
思路:有m个水龙头,i个人,那就m个人同时接水,哪个人先接完就用剩下的人去代替他,直到所有人都接完水
那就用数组a[]来处理,当a[i]==0(即接完水时),令a[i]=a[t](相当于让没打水的人把打完水的人替换掉)
完整代码
#include<bits/stdc++.h>
using namespace std;
int w[10005];
int main()
{
int time,people,n,m,i;
cin>>n>>m;
people=m+1;
for(i=1;i<=n;i++)
{
cin>>w[i];
}
while(people<m+n+1)
{
for(i=1;i<=m;i++)
{
w[i]--;
if(w[i]==0)
{
w[i]=w[people];
people++;
}
}
time++;
}
cout<<time;
return 0;
}
P3395 路障
题目描述
B 君站在一个 n×n 的棋盘上。最开始,B君站在 (1,1)(1,1) 这个点,他要走到 (n,n) 这个点。
B 君每秒可以向上下左右的某个方向移动一格,但是很不妙,C 君打算阻止 B 君的计划。
每秒结束的时刻,C 君 会在(x,y) 上摆一个路障。B 君不能走在路障上。
B 君拿到了 C 君准备在哪些点放置路障。所以现在你需要判断,B 君能否成功走到 (n,n)。
保证数据足够弱:也就是说,无需考虑“走到某处然后被一个路障砸死”的情况,因为答案不会出现此类情况。
输入格式
首先是一个正整数 T,表示数据组数。
对于每一组数据:
第一行,一个正整数 n。
接下来 2n−2 行,每行两个正整数 x 和 y,意义是在那一秒结束后,(x,y) 将被摆上路障。
输出格式
对于每一组数据,输出 Yes
或 No
,回答 B 君能否走到(n,n)。
思路:除去路障这就是一道简单的BFS模板题
那要怎么处理路障呢?
可以用一个计数单位来计数(记录该点路障生成时的步数),如果当走到有路障会降落的点的时候,当前步数小于路障生成所需步数,那便可以通过,否则不行;
完整代码:ps(第一次提交给我干爆内存了,让ai帮我优化了一下,删去了一些不必要的全局变量,改为局部变量)
超时代码:
#include<bits/stdc++.h>
using namespace std;
struct note
{
int x;
int y;
int s;
};
int a[1005][1005]={0};
int book[1005][1005]={0};
int ne[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
int n;
void bfs()
{
queue<note>q;
note st,next,po;
st.x=1;st.y=1;st.s=0;//初始x,y位置以及步数s
book[1][1]=1;
q.push(st);
while(!q.empty())
{
po=q.front();
q.pop();
if(po.x==n&&po.y==n)
{
cout<<"Yes"<<endl;
return;
}
next.s=po.s+1;
for(int k=0;k<4;k++)
{
next.x=po.x+ne[k][0];
next.y=po.y+ne[k][1];
if(next.x>=1&&next.x<=n&&next.y>=1&&next.y<=n)
{
if(a[next.x][next.y]==0||next.s<=a[next.x][next.y])
{
if(book[next.x][next.y]==0)
book[next.x][next.y]=1;
q.push(next);
}
}
}
}
cout<<"No"<<endl;
return;
}
int main()
{
int t,sx,sy;
cin>>t;
while(t--)
{
memset(a,0,sizeof(a));
memset(book,0,sizeof(book));
cin>>n;
if(n==1){
cout<<"Yes"<<endl;
continue;
}
for(int j=1;j<=2*n-2;j++)
{
cin>>sx>>sy;
a[sx][sy]=j;
}
bfs();
}
return 0;
}
优化后代码:
#include<bits/stdc++.h>
using namespace std;
struct note
{
int x;
int y;
int s;
};
const int MAX_N = 1005;
int a[MAX_N][MAX_N] = {0};
int book[MAX_N][MAX_N] = {0};
int ne[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
void bfs(int n)
{
queue<note> q;
note st = {1, 1, 0}; // 结构体初始化
book[1][1] = 1;
q.push(st);
while (!q.empty())
{
note po = q.front();
q.pop();
if (po.x == n && po.y == n)
{
cout << "Yes" << endl;
return;
}
for (int k = 0; k < 4; k++)
{
int nx = po.x + ne[k][0];
int ny = po.y + ne[k][1];
if (nx >= 1 && nx <= n && ny >= 1 && ny <= n && (a[nx][ny] == 0 || po.s + 1 <= a[nx][ny]) && book[nx][ny] == 0)
{
book[nx][ny] = 1;
q.push({nx, ny, po.s + 1});
}
}
}
cout << "No" << endl;
}
int main()
{
int t, n, sx, sy;
cin >> t;
while (t--)
{
memset(a, 0, sizeof(a));
memset(book, 0, sizeof(book));
cin >> n;
if (n == 1)
{
cout << "Yes" << endl;
continue;
}
for (int j = 1; j <= 2 * n - 2; j++)
{
cin >> sx >> sy;
a[sx][sy] = j;
}
bfs(n);
}
return 0;
}
ACWing5462. 修改数列
给定一个长度为 n的正整数数列 a1,a2,…,an。
你可以对其中任意个(可以是 00 个)元素进行修改。
但是,每个元素最多只能修改一次,每次修改:要么令其加 11,要么令其减 11。
请问,至少需要修改多少个元素,才能使得数列 a 变成一个等差数列。
输入格式
第一行包含整数 n。
第二行包含 n 个整数 a1,a2,…,an
输出格式
一个整数,表示需要修改的元素的最少数量。
如果无解,则输出 -1
。
思路:
等差数列
首尾项相减除以(项数-1)得到公差
每个元素最多修改一次,看他离要求差多少,大于1就不行直接输出-1;
首尾项也可以通过修改增减1来变化公差d的大小
1.首尾项都不修改
2.首项+1,2项不改(1)(此时step(修改次数初始值为1))
3.首项-1,2项不改(1)
4.首项不改,2项+1(1)
5.首项不改,2项-1(1)
6.首项+1,2项+1(2)
7.首项-1,2项-1(2)
8.首项+1,2项-1(2)
9.首项-1,2项+1(2)
然后遍历数据
从第三项开始,到第n项;
用i来表示项数,公差d,则有a1+d*(i-1)=ai
然后用min函数来更新最小修改数
一旦有超出的结束这次遍历,开始下一次遍历
完整代码:
#include<bits/stdc++.h>
using namespace std;
int n;
int p=99999999;
int a[100005];
int cal(int x,int y)//x指首项减,y指第2项减
{
int s=a[1]+x;
int d=a[2]+y-s;
int step=abs(x)+abs(y);
for(int i=3;i<=n;i++)
{
int t=d*(i-1)+s;
if(abs(t-a[i])>1)//超过可以修改的次数
{
return p;
}
else
{
step+=abs(t-a[i]);
}
}
return step;
}
int main()
{
int ans=p;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
for(int i=-1;i<=1;i++)
{
for(int j=-1;j<=1;j++)
{
ans=min(ans,cal(i,j));
}
}
if(ans==p)
{
cout<<-1;
}
else
{
cout<<ans<<endl;
}
return 0;
}
P1022 [NOIP2000 普及组] 计算器的改良
题目背景
NCL 是一家专门从事计算器改良与升级的实验室,最近该实验室收到了某公司所委托的一个任务:需要在该公司某型号的计算器上加上解一元一次方程的功能。实验室将这个任务交给了一个刚进入的新手 ZL 先生。
题目描述
为了很好的完成这个任务,ZL 先生首先研究了一些一元一次方程的实例:
- 4+3x=8
- 6a−5+1=2−2a。
- -5+12y=0。
ZL 先生被主管告之,在计算器上键入的一个一元一次方程中,只包含整数、小写字母及 +
、-
、=
这三个数学符号(当然,符号“-
”既可作减号,也可作负号)。方程中并没有括号,也没有除号,方程中的字母表示未知数。
你可假设对键入的方程的正确性的判断是由另一个程序员在做,或者说可认为键入的一元一次方程均为合法的,且有唯一实数解。
输入格式
一个一元一次方程。
输出格式
解方程的结果(精确至小数点后三位)。
一道模拟题,把数字移动到一边,把x移动到另一边,就行了,这里可以通过一个数字1来处理,
检测字符串“=”的时候变号,对于数字的累加也可以用一个1,前面遇见加号就变成+1,遇见减号就变成-1
完整代码:
#include <bits/stdc++.h>
using namespace std;
int main()
{
int a[1000];
int point=1,flag=1,done=1;
double x=0.0,sum=0.0;
char s,r;
memset(a,0,sizeof(a));
while(s!='\n')
{
s=getchar();
if(s=='-'){++flag;point=-1;}
if(s=='+'){++flag;point=1;}
if(s=='='){++flag;point=1;done=-1;}
if(s>='0'&&s<='9')
{
if(!a[flag])
{
a[flag]=(s-'0')*point*done;
}
else
{
a[flag]=a[flag]*10+(s-'0')*point*done;
}
}
if(s>='a'&&s<='z')
{
r=s;
if(a[flag]!=0)
{
x+=a[flag]*done;
a[flag]=0;
}
else
{
x+=done*point;
}
--flag;
}
}
for(int i=0;i<=flag;++i)
{
sum+=a[i];
}
x*=-1;
if(!(sum/x))
cout<<r<<"="<<"0.000";
else
{
cout<<r<<"="<<fixed<<setprecision(3)<<sum/x;
}
return 0;
}