soj 2013 weekly-2 7574-7675 7691-7593

本文解析了四个经典算法题目,包括石头传递问题、岛屿数量计算、等式字母替换问题及最短时间路径寻找,并提供了详细的代码实现。

7674

题意:n个人(0~n-1)坐成一圈,有p个石头,从第0个人开始,如果还有石头,那么他从中取出一个,如果没有石头,那么他把自己所有的石头贡献出来,接着轮到下一个,问最后p个石头会到谁那去。

思路:简单模拟即可。

#include <cstdio>
#include <cstring>
int n, p, arr[55], curP, curN;
int main()
{
	while (true)
	{
		scanf("%d%d",&n,&p);
		if (n == 0 && p == 0) break;
		memset(arr, 0, sizeof(arr));
		curN = p;
		curP = 0;
		while (true)
		{
			if (arr[curP] == p) break;
			else if (curN > 0)
			{
				curN --;
				arr[curP] ++;
			}
			else
			{
				curN = arr[curP];
				arr[curP] = 0;
			}
			curP = (curP+1) % n;
		}
		printf("%d\n", curP);
	}
}
7675

题意:求联通块的数目

思路:广搜深搜皆可

#include <cstdio>
#include <queue>
using namespace std;

int w, h, ans;
bool g[55][55];
int dir[8][2] = {{-1,-1},{-1,0},{-1,1},{0,1},{0,-1},{1,-1},{1,0},{1,1}};
struct Point
{
	int r, c;
	Point() {}
	Point(int _r, int _c): r(_r), c(_c) {}
	Point next(int k) { return Point(r+dir[k][0], c+dir[k][1]); }
	bool leagal() { return r>=0 && r<h && c>=0 && c<w && g[r][c]==1; }
	void setSea() { g[r][c] = 0; }
} cur, nxt;
queue <Point> Q;
int main()
{
	while (true)
	{
		scanf("%d%d",&w,&h);
		if (w == 0 && h == 0) break;
		for (int i = 0; i < h; ++ i)
			for (int j = 0; j < w; ++ j)
				scanf("%d",&g[i][j]);
		ans = 0;
		for (int i = 0; i < h; ++ i)
		{
			for (int j = 0; j < w; ++ j)
			{
				if (g[i][j] == 1)
				{
					ans ++;
					cur = Point(i,j);
					cur.setSea();
					Q.push(cur);
					while (!Q.empty())
					{
						cur = Q.front();
						Q.pop();
						for (int k = 0; k < 8; ++ k)
						{
							nxt = cur.next(k);
							if (nxt.leagal())
							{
								nxt.setSea();
								Q.push(nxt);
							}
						}
					}
				}
			}
		}
		printf("%d\n", ans);
	}
}
7691

题意:给一个字母的等式,每个字母代表不同的数字,每个数字被不同的字母代表着,不能有除零外的以零打头的数,问有多少种字母的复制方法。

思路:记录每一个字母的权值,(在十位的字母权值+10,类推)。然后深搜,注意打头的字母不能为零的情况。这样暴力深搜会超时(我做的时候是超时了)。加一个非常简单的剪枝,就是在搜之前判断当前最大和最小的可能值,如果最大值也比零小或者最小值也比零大,那么不必再搜索下去。

#include <cstdio>
#include <cstdlib>
#include <cstring>

char s[15];
int n, c[30], l, ans;
int data[30], numb[30];
bool used[30], frst[30], vis[15];
void dfs(int d, int sum)
{
	int x = sum;
	for (int i = d; i < l; ++ i)
		if (c[data[i]] > 0) x += c[data[i]] * 9;
	if (x < 0) return ;
	x = sum;
	for (int i = d; i < l; ++ i)
		if (c[data[i]] < 0) x += c[data[i]] * 9;
	if (x > 0) return ;
	if (d == l)
	{
		if (sum == 0) ans ++;
		return ;
	}
	for (int i = 0; i < 10; ++ i) if (!vis[i])
	{
		if (frst[data[d]] == 1 && i == 0) continue;
		numb[d] = i;
		vis[i] = true;
		dfs(d+1, sum+c[data[d]]*i);
		vis[i] = false;
	}
}
int main()
{
	while (scanf("%d", &n), n)
	{
		memset(used, false, sizeof(used));
		memset(frst, false, sizeof(frst));
		memset(c, 0, sizeof(c));
		for (int i = 0; i < n; ++ i)
		{
			scanf("%s", s);
			l = strlen(s);
			if (l > 1) frst[s[0]-'A'] = true;
			for (int j = l-1, pow10 = 1; j >= 0; -- j, pow10 *= 10)
			{
				used[s[j]-'A'] = true;
				c[s[j]-'A'] += ((i==n-1) ? (-pow10) : pow10);
			}
		}
		l = 0;
		for (int i = 0; i < 26; ++ i)
			if (used[i]) data[l++] = i;
		ans = 0;
		dfs(0, 0);
		printf("%d\n", ans);
	}
}
7692

题意:给一个n个城市m条路径(有速度上限,有权值)的无向图,给出起点终点,每经过一个城市,速度可以+1,+0,-1,问从起点到终点的最短时间。

思路:直接广搜,可以用优先队列,速度上限最大不过30,城市最多不过30个,很好判重。值得注意的题目的一个信息是:不能走U字型的路,被这个坑了很多时间,也就是不能1-2-1这样走。

#include <cstdio>
#include <queue>
#include <cstring>
using namespace std;
#define INF 1e20
#define N 55
struct Edge
{
	int ed, dist, limit;
	Edge() {}
	Edge(int _e, int _d, int _l): ed(_e), dist(_d), limit(_l) {}
};
vector <Edge> adj[N];
double best[N][N][N];
bool visit[N][N][N];
int n, m, s, e;
struct Node
{
	int preP, curP, v;
	double t;
	Node() {}
	Node(int _pp, int _cp, int _v, double _t): preP(_pp), curP(_cp), v(_v), t(_t) {}
	bool operator < (const Node &obj) const { return t > obj.t;}
}cur, nxt;
bool bfs()
{
	priority_queue <Node> Q;
	Q.push(Node(s,s,0,0));
	best[s][0][s] = 0;
	while (!Q.empty())
	{
		cur = Q.top();
		Q.pop();
		if (visit[cur.curP][cur.v][cur.preP]) continue;
		else visit[cur.curP][cur.v][cur.preP] = true;
		if (cur.curP==e && cur.v==1)
		{
			printf("%.5lf\n", cur.t);
			return true;
		}
		nxt.preP = cur.curP;
		for (int i = adj[cur.curP].size()-1; i >= 0; -- i)
		{
			nxt.curP = adj[cur.curP][i].ed;
			if (nxt.curP == cur.preP) continue;
			for (int dv = -1; dv <= 1; ++ dv)
			{
				nxt.v = cur.v+dv;
				if (!visit[nxt.curP][nxt.v][nxt.preP] && nxt.v>0 && nxt.v<=adj[cur.curP][i].limit)
				{
					nxt.t = cur.t + adj[cur.curP][i].dist*1.0/nxt.v;
					if (best[nxt.curP][nxt.v][nxt.preP] > nxt.t)
					{
						best[nxt.curP][nxt.v][nxt.preP] = nxt.t;
						Q.push(nxt);
					}
				}
			}
		}
	}
	return false;
}
int main()
{
	while (scanf("%d%d",&n,&m) != EOF)
	{
		if (n==0 && m==0) break;
		scanf("%d%d",&s,&e);
		for (int i = 0; i < N; ++ i)
		{
			adj[i].clear();
			for (int j = 0; j < N; ++ j)
			{
				for (int k = 0; k < N; ++ k)
				{
					visit[i][j][k] = false;
					best[i][j][k] = INF;
				}
			}
		}
		for (int i=0,u,v,d,c; i < m; ++ i)
		{
			scanf("%d%d%d%d",&u,&v,&d,&c);
			adj[u].push_back(Edge(v,d,c));
			adj[v].push_back(Edge(u,d,c));
		}
		if (!bfs()) puts("unreachable");
	}
}
7693

题意:给两堆数{X},{Y},如果{X}中的某个数和{Y}中的某个数的GCD大于1,那么称这两个数可以配对,问最多有多少个配对。

思路:赤裸裸的二分图匹配问题。

#include <cstdio>
#include <cstring>
#define N 505
int nx, ny;
int cx[N], cy[N];
bool bmap[N][N];
bool bmask[N];
bool gcd(int a, int b)
{
	int mod;
	while (mod = a % b)
	{
		a = b;
		b = mod;
	}
	return b > 1;
}
int findPath(int u)
{
	for (int i = 0; i < ny; ++ i)
	{
		if (bmap[u][i] && !bmask[i])
		{
			bmask[i] = 1;
			if (cy[i] == -1 || findPath(cy[i]))
			{
				cy[i] = u;
				cx[u] = i;
				return 1;
			}
		}
	}
	return 0;
}
int maxMatch()
{
	int res = 0;
	memset(cx, -1, sizeof(cx));
	memset(cy, -1, sizeof(cy));
	for (int i = 0; i < nx; ++ i)
	{
		if (cx[i] == -1)
		{
			memset(bmask, 0, sizeof(bmask));
			res += findPath(i);
		}
	}
	return res;
}
int main()
{
	while (true)
	{
		scanf("%d%d",&nx,&ny);
		if (nx == 0 && ny == 0) break;
		memset(bmap, 0, sizeof(bmap));
		for (int i = 0; i < nx; ++ i)
			scanf("%d", &cx[i]);
		for (int i = 0; i < ny; ++ i)
		{
			scanf("%d", &cy[i]);
			for (int j = 0; j < nx; ++ j)
			{
				if (gcd(cy[i], cx[j]))
					bmap[j][i] = 1;
			}
		}
		printf("%d\n", maxMatch());
	}
}

(1)普通用户端(全平台) 音乐播放核心体验: 个性化首页:基于 “听歌历史 + 收藏偏好” 展示 “推荐歌单(每日 30 首)、新歌速递、相似曲风推荐”,支持按 “场景(通勤 / 学习 / 运动)” 切换推荐维度。 播放页功能:支持 “无损音质切换、倍速播放(0.5x-2.0x)、定时关闭、歌词逐句滚动”,提供 “沉浸式全屏模式”(隐藏冗余控件,突出歌词与专辑封面)。 多端同步:自动同步 “播放进度、收藏列表、歌单” 至所有登录设备(如手机暂停后,电脑端打开可继续播放)。 音乐发现与管理: 智能搜索:支持 “歌曲名 / 歌手 / 歌词片段” 搜索,提供 “模糊匹配(如输入‘晴天’联想‘周杰伦 - 晴天’)、热门搜索词推荐”,结果按 “热度 / 匹配度” 排序。 歌单管理:创建 “公开 / 私有 / 加密” 歌单,支持 “批量添加歌曲、拖拽排序、一键分享到社交平台”,系统自动生成 “歌单封面(基于歌曲风格配色)”。 音乐分类浏览:按 “曲风(流行 / 摇滚 / 古典)、语言(国语 / 英语 / 日语)、年代(80 后经典 / 2023 新歌)” 分层浏览,每个分类页展示 “TOP50 榜单”。 社交互动功能: 动态广场:查看 “关注的用户 / 音乐人发布的动态(如‘分享新歌感受’)、好友正在听的歌曲”,支持 “点赞 / 评论 / 转发”,可直接点击动态中的歌曲播放。 听歌排行:个人页展示 “本周听歌 TOP10、累计听歌时长”,平台定期生成 “全球 / 好友榜”(如 “好友中你本周听歌时长排名第 3”)。 音乐圈:加入 “特定曲风圈子(如‘古典音乐爱好者’)”,参与 “话题讨论(如‘你心中最经典的钢琴曲’)、线上歌单共创”。 (2)音乐人端(创作者中心) 作品管理: 音乐上传:支持 “无损音频(FLAC/WAV)+ 歌词文件(LRC)+ 专辑封面” 上传,填写 “歌曲信息
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值