2024/1/30

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

  • 24
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值