[PAT-A 1016]Phone Bills

本文详细介绍了如何设计一个电话计费系统,包括记录排序、有效通话记录判断、资费计算等核心步骤。通过实例讲解了如何对通话记录进行排序、判断有效通话记录,并计算通话时长及费用。

在这里插入图片描述
题目大意:
给出24h中每个小时区间内的资费,给出N个通话记录点,每个记录点记录了姓名,当前时刻:(月:日:时:分)通话开始(on-line)结束:(off-line) 对每个人的有效通话记录进行资费计算。
”有效通话记录“:可以理解为对同一个人的通话记录按照时间先后顺序排序后一对连续的on-line off-line

思路:
对所有记录进行排序,并且判断是否存在有效通话记录,如果有则输出有效通话记录,同时计算时长,统计资费

输入信息结构体定义:

struct Record {
	char name[25];
	int month, dd, hh, mm;
	bool status;//statue==ture:on-line status==false :off-line
}rec[maxn], temp;

1.排序cmp函数:
1)用户名不同,以用户名从小到大。
2) 用户名相同,以时间从小到大,即月份,日期,小时,分钟的顺序有效到大的顺序。

bool cmp(Record a, Record b) {
	int s = strcmp(a.name, b.name);
	if (s != 0)return s < 0;
	else if (a.month != b.month)return a.month < b.month;
	else if (a.dd != b.dd)return a.dd < b.dd;
	else if (a.hh != b.hh)return a.hh < b.hh;
	else return a.mm < b.mm;
}

2.判断是否存在有效通话记录(即是否需要输出)

int on,int next;//on表示该用户第一条记录,即开始,next表示当先下一条记录
while(on<总数){
	int needPrint=0;//needPrint=0为初值,=1为匹配到on-line =2表示需要输出
	next=on;
	while(next<总数&&姓名匹配还是当前用户){
		if(needPrint==0&&当前记录状态为on-line)needPrint=1;
		else if(needPrint==1&&当前记录状态为off-line)needPrint=2;//配对成功表示需要输出
		next++;
	}
	if(needPrint<2){//如果没有匹配到的,就继续下一个用户
		on=next;
		continue;
	}
}

3.如果needPrint==2,输出有效记录
遍历该用户列表,找见当前记录为on-line并且下一条记录为off-line的记录,对该记录进行资费统计
(资费统计)可以统计一共有多少分钟,根据每个时段的的价位累加
用来计算两个时间之间的差值的算法(常考)

//也可以推到年月日,计算天数
while(start.day < end.day || start.hour < end.hour || start.minute < end.minute){
    start.minute++;
    if(start.minute == 60){
        start.minute = 0;
        start.hour++;
    }
    if(start.hour = 24){
        start.hour = 0;
        start.day++;
    }
}

本题的版本:

void get_ans(int on, int off, int &time, int &money) {
	temp = rec[on];
	while (temp.dd < rec[off].dd || temp.hh < rec[off].hh || temp.mm < rec[off].mm) {
		time++;
		money += toll[temp.hh];
		temp.mm++;
		if (temp.mm >= 60) {
			temp.mm = 0;
			temp.hh++;
		}
		if (temp.hh >= 24) {
			temp.hh = 0;
			temp.dd++;
		}
	}
}

最后累加该用户的所有通话记录的总费用并输出。(资费单价是美分,要换算成美元)

4.进行下一个用户

AC代码:

//PAT_A 1016
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 1010;
int toll[25];
struct Record {
	char name[25];
	int month, dd, hh, mm;
	bool status;
}rec[maxn], temp;
bool cmp(Record a, Record b) {
	int s = strcmp(a.name, b.name);
	if (s != 0)return s < 0;
	else if (a.month != b.month)return a.month < b.month;
	else if (a.dd != b.dd)return a.dd < b.dd;
	else if (a.hh != b.hh)return a.hh < b.hh;
	else return a.mm < b.mm;
}
void get_ans(int on, int off, int& time, int& money) {
	temp = rec[on];
	while (temp.dd < rec[off].dd || temp.hh < rec[off].hh || temp.mm < rec[off].mm) {
		time++;
		money += toll[temp.hh];
		temp.mm++;
		if (temp.mm >= 60) {
			temp.mm = 0;
			temp.hh++;
		}
		if (temp.hh >= 24) {
			temp.hh = 0;
			temp.dd++;
		}
	}
}
int main() {
	for (int i = 0; i < 24; i++) {
		scanf("%d", &toll[i]);
	}
	int n;
	char line[10];
	scanf("%d", &n);
	for (int i = 0; i < n; i++) {
		(void)scanf("%s", rec[i].name);
		(void)scanf("%d:%d:%d:%d", &rec[i].month, &rec[i].dd, &rec[i].hh, &rec[i].mm);
		(void)scanf("%s", line);
		if (strcmp(line, "on-line") == 0)rec[i].status = true;
		else rec[i].status = false;
	}
	sort(rec, rec + n, cmp);
	int on = 0, off, next;
	while (on < n) {//循环处理单个用户的所有记录
		int needPrint = 0;//表示该用户是否需要输出
		next = on;//从当前位置开始寻找下一个用户,next中存储的是下一个用户的首地址
		while (next < n && strcmp(rec[next].name, rec[on].name) == 0) {
			if (needPrint == 0 && rec[next].status == true)needPrint = 1;//找到on 置1
			else if (needPrint == 1 && rec[next].status == false)needPrint = 2;//on之后找到off 置2
			next++;
		}
		if (needPrint < 2) {//没有配对的on-off
			on = next;
			continue;
		}
		int AllMoney = 0;
		printf("%s %02d\n", rec[on].name, rec[on].month);
		while (on < next) {
			while (on < next - 1 && !(rec[on].status == true && rec[on + 1].status == false))on++;//找到连续的on-off
			off = on + 1;
			if (off == next) {//表示已经到了最后一个用户,开始处理下一个用户
				on = next;
				break;
			}
			printf("%02d:%02d:%02d ", rec[on].dd, rec[on].hh, rec[on].mm);
			printf("%02d:%02d:%02d ", rec[off].dd, rec[off].hh, rec[off].mm);
			int time = 0, money = 0;
			get_ans(on, off, time, money);
			AllMoney += money;
			printf("%d $%.2f\n", time, money / 100.0);
			on = off + 1;
		}
		printf("Total amount: $%.2f\n", AllMoney / 100.0);
	}
	return 0;
}
在 .NET 平台上实现与微信支付 V3 相关的转账功能,尤其是商家转账到零钱的操作,需要遵循微信支付平台提供的 API 接口规范。以下是实现此类转账功能的关键步骤和技术要点。 ### 转账请求的准备工作 1. **配置参数**:需要从微信支付商户平台获取必要的配置信息,包括 `appid`、`mchId`(商户号)、`serialNo`(证书序列号)等。这些信息通常存储在配置文件中,以便于安全管理和访问。 2. **生成唯一交易编号**:每次转账请求都需要一个唯一的交易编号 `partnerTradeNo`,通常由开发者生成,格式可以是时间戳加上随机字符串,例如 `xcx20200520132935120`。 3. **日志记录**:为了便于调试和问题追踪,建议在代码中加入详细的日志记录功能。例如,记录转账开始时间、转账金额、用户标识 `openID` 以及转账结果等信息。 ```csharp Log.Info("开始发起商户转账到零钱:", "开===始"); Log.Info("开始发起商户转账到零钱:", "获取提现金额,amount=" + amount); Log.Info("开始发起商户转账到零钱:", "获取客户信息,openID=" + openID); ``` 4. **调用转账接口**:使用 `appid`、`mchId`、`serialNo`、`openID`、`partnerTradeNo` 和金额 `amount` 等参数调用微信支付 V3 的转账接口。此接口返回的结果包含 `out_batch_no`、`batch_id` 和 `create_time` 等字段,用于确认转账状态和时间。 ```csharp string partnerTradeNo = "xcx" + DateTime.Now.ToString("yyyyMMddHHmmfff"); string result = ResultV3Withdraw.WithDrawsToWx(appid, mchId, serialNo, openID, partnerTradeNo, Convert.ToInt32(amount * 100)); JObject objs = JObject.Parse(result); Log.Info("商户转账到零钱结果out_batch_no=", objs["out_batch_no"].ToString()); Log.Info("商户转账到零钱结果batch_id=", objs["batch_id"].ToString()); Log.Info("商户转账到零钱结果create_time=", objs["create_time"].ToString()); ``` ### 转账请求的响应处理 1. **解析响应数据**:微信支付 V3 接口返回的数据通常为 JSON 格式,包含 `out_batch_no`(商户批次单号)、`batch_id`(微信支付批次单号)、`state`(批次状态) 和 `update_time`(最后更新时间) 等字段。这些字段用于确认转账是否成功以及当前的状态。 ```json { "out_bill_no": "plfk2020042013", "transfer_bill_no": "1330000071100999991182020050700019480001", "state": "CANCELING", "update_time": "2015-05-20T13:29:35.120+08:00" } ``` 2. **异常处理**:在处理转账请求时,可能会遇到网络错误、参数错误或权限问题等情况。因此,建议在代码中加入异常处理机制,确保程序的健壮性和稳定性。 ```csharp try { string result = ResultV3Withdraw.WithDrawsToWx(appid, mchId, serialNo, openID, partnerTradeNo, Convert.ToInt32(amount * 100)); JObject objs = JObject.Parse(result); Log.Info("商户转账到零钱结果out_batch_no=", objs["out_batch_no"].ToString()); Log.Info("商户转账到零钱结果batch_id=", objs["batch_id"].ToString()); Log.Info("商户转账到零钱结果create_time=", objs["create_time"].ToString()); } catch (Exception ex) { Log.Error("转账过程中发生异常:", ex.Message); } ``` 3. **状态更新与通知**:对于某些转账操作,如撤销转账,需要定期查询转账状态,确保操作已完成。可以通过调用微信支付 V3 的查询接口来获取最新的转账状态,并根据状态更新本地数据库或发送通知给用户。 ### 撤销转账操作 1. **发起撤销请求**:如果需要撤销一笔已经发起的转账,可以通过微信支付 V3 提供的撤销接口完成。撤销请求需要提供 `out_batch_no` 或 `batch_id` 作为参数,用于标识要撤销的转账批次。 2. **处理撤销响应**:撤销请求成功后,返回的响应中将包含 `out_bill_no`、`transfer_bill_no`、`state` 和 `update_time` 等字段,表示撤销操作的状态和时间。开发者可以根据这些信息判断撤销是否成功,并更新相关记录。 ```json { "out_bill_no": "plfk2020042013", "transfer_bill_no": "1330000071100999991182020050700019480001", "state": "CANCELING", "update_time": "2015-05-20T13:29:35.120+08:00" } ``` 3. **后续处理**:撤销操作完成后,建议通知用户转账已被撤销,并根据业务需求进行相应的后续处理,如退款、重新发起转账等。 ### 总结 在 .NET 平台上实现微信支付 V3 的转账功能,主要包括配置参数设置、生成唯一交易编号、调用转账接口、处理响应数据、异常处理以及撤销转账等步骤。通过合理的设计和实现,可以确保转账操作的安全性、可靠性和可追溯性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值