您的位置:首页 > 编程语言 > C语言/C++

2018高教社杯B题 RGV动态调度 c++模拟

2020-01-12 18:52 316 查看

##2018高教社杯B题 RGV动态调度 c++模拟

本人软件工程专业,怀着提高数学能力的初衷参加数学建模竞赛,万万没想到居然在这道题里提高了编程能力。。甚至之前没学懂的指针都搞懂了,连调试程序也得心应手了:)
虽然答辩时被怼这不是程序设计大赛而是数学建模竞赛,但感觉收获颇多,代码也颇有价值,可用在论文最后动态模拟RGV工作流程。
注:程序中只用了数组、指针、动态生成随机数等最基本C++技术,可放心食用
代码如下:

  • 一道工序
#include "stdafx.h"
#include <math.h>
#include <iostream>
#include <ctime>
#include <random>
#define random(a,b) (rand()%(b-a)+a)

int m = 545;//CNC上单个产品加工时间
int erro = 0;
int Time = 0, H = 0, W = 0, U = 0, Q = 0; //Time为系统从开始到某时刻的时间;H为系统运动消耗时间;W为系统等待时间;U为系统上下料时间;Q为系统清洗熟料时间
int h = 0, w = 0, u = 0, u1 = 27, u2 = 32, q = 25, h1 = 18, h2 = 32, h3 = 46;//u1为奇数CNC上下料时间,u2为偶数CNC上下料时间
int place1 = 1, place2 = 2, place3 = 3, place4 = 4;//设定RGV轨道上四个位置节点
int n = 0;//产出熟料数量

class CNC {
public:
int T = 0;
int status1 = 1;
int status2 = 0;
int Cp = place1;
int products = 0;
};

class RGV {
public:
int RpNow = place1;//RGV当前所处位置
int RpNext = place4;//RGV下一个遍历的位置
};

void TimeCost(CNC *k);
void Pick1(CNC *k, int u);
void Pick2(CNC *k, int u);
void Wait(CNC k[8]);
void route(CNC k[8], RGV *s);

int main()
{
srand(unsigned(time(0)));
RGV rgv;//一台RGV

CNC cnc[8];//一共8台CNC机器且都可被RGV使用
cnc[1].Cp = place1, cnc[2].Cp = place2;
cnc[3].Cp = place2, cnc[4].Cp = place3;
cnc[5].Cp = place3, cnc[6].Cp = place4;
cnc[7].Cp = place4, cnc[0].Cp = place1;

//RGV工作流程:

while (Time <= 8 * 3600)
{

//更新CNC的请求状态
TimeCost(cnc);

//系统进入等待时间
if ((cnc[0].status1 == 0 && cnc[0].status2 == 0) && (cnc[1].status1 == 0 && cnc[1].status2 == 0) && (cnc[2].status1 == 0 && cnc[2].status2 == 0) && (cnc[3].status1 == 0 && cnc[3].status2 == 0) && (cnc[4].status1 == 0 && cnc[4].status2 == 0) && (cnc[5].status1 == 0 && cnc[5].status2 == 0) && (cnc[6].status1 == 0 && cnc[6].status2 == 0) && (cnc[7].status1 == 0 && cnc[7].status2 == 0))
{

Wait(cnc);

}
//选择下一个去的位置
else
{

route(cnc, &rgv);

}

}

//计算产出的总产品量
printf("总共生产了%d个熟料\n", n);
printf("出了%d次错", erro);

getchar();

return 0;
}

//判断某台CNC是否在加工产
void TimeCost(CNC k[8])
{
for (int r = 0;r < 8;r++)
{
if (abs((Time - k[r].T)) >= m)
{

k[r].status1 = 0;
k[r].status2 = 1;
}
}

}

void Pick1(CNC *k, int u)
{
k->status1 = 0;
k->status2 = 0;
U += u;//增加单位上下料时间
Time += u;
if (random(0, 100) == 10)
{
k->T = Time + random(10 * 60, 20 * 60) + random(0, m);
erro++;
}
else {
k->T = Time;//记录CNC开始工作时刻
}

//printf("%d\n", (k->T)-50);
}

void Pick2(CNC *k, int u)
{

k->status1 = 0;
k->status2 = 0;
k->products++;
U += u;//增加单位上下料时间
Time += u;
if (random(0,100)==10)
{
k->T = Time + random(10 * 60, 20 * 60) + random(0, m);
erro++;
}
else {
k->T = Time;//记录CNC开始工作时刻
Q += q;//增加单位清洗时间
Time += q;
n++;
}

printf("%d\n", Time - 50);
}

void Wait(CNC k[8]) {
int temp = 10000000;
for (int n = 0;n<8;n++)
{
if (temp >= k
.T)
{
temp = k
.T;
}
}
Time += (m - (Time - temp));//增加最小等待时间
}

void route(CNC k[8], RGV *s) {
int c = 5;
int d = 0;
for (int i = 0;i < 8;i++)
{
if (k[i].status1 == 1 || k[i].status2 == 1)
{
if (abs(k[i].Cp - s->RpNow)< c)
{

s->RpNext = k[i].Cp;
c = abs(s->RpNext - s->RpNow);
d = i;

}
/*
else
{
if (k[i].status2 == 1)    //pick2优先
{
s->RpNext = k[i].Cp;
c = abs(s->RpNext - s->RpNow);
d = i;
}
else
{
s->RpNext = k[i].Cp;
c = abs(s->RpNext - s->RpNow);
d = i - 1;

}

}
*/

}

}

//区别移动距离
if (c = 0)
h = 0;
else if (c = 1)
h = h1;
else if (c = 2)
h = h2;
else if (h = 3)
h = h3;

H = h;
Time += h;
if (k[d].status2 == 1)  //判断CNC为奇还是偶
{
if (d % 2 == 0)
u = u2;
else if (d % 2 != 0)
u = u1;
Pick2(&k[d], u);

}
else if (k[d].status1 == 1)
{
if (d % 2 == 0)
u = u2;
else if (d % 2 != 0)
u = u1;
Pick1(&k[d], u);

}

s->RpNow = s->RpNext;//更新RGV位置
}
  • 一道工序且CNC有几率产生故障
#include "stdafx.h"
#include <math.h>
#include <iostream>
#include <ctime>
#include <random>
#define random(x) rand()%(x)

int m = 545;//CNC上单个产品加工时间
int Time = 0, H = 0, W = 0, U = 0, Q = 0; //Time为系统从开始到某时刻的时间;H为系统运动消耗时间;W为系统等待时间;U为系统上下料时间;Q为系统清洗熟料时间
int h = 0, w = 0, u = 0, u1 = 27, u2 = 32, q = 25, h1 = 18, h2 = 32, h3 = 46;//u1为奇数CNC上下料时间,u2为偶数CNC上下料时间
int place1 = 1, place2 = 2, place3 = 3, place4 = 4;//设定RGV轨道上四个位置节点
int n = 0;//产出熟料数量

class CNC {
public:
int T = 0;
int status1 = 1;
int status2 = 0;
int Cp = place1;
int products = 0;
};

class RGV {
public:
int RpNow = place1;//RGV当前所处位置
int RpNext = place4;//RGV下一个遍历的位置
};

void TimeCost(CNC *k);
void Pick1(CNC *k, int u);
void Pick2(CNC *k, int u);
void Wait(CNC k[8]);
void route(CNC k[8], RGV *s);

int main()
{
srand(unsigned(time(0)));
RGV rgv;//一台RGV

CNC cnc[8];//一共8台CNC机器且都可被RGV使用
cnc[1].Cp = place1, cnc[2].Cp = place2;
cnc[3].Cp = place2, cnc[4].Cp = place3;
cnc[5].Cp = place3, cnc[6].Cp = place4;
cnc[7].Cp = place4, cnc[0].Cp = place1;

//RGV工作流程:

while (Time <= 8 * 3600)
{

//更新CNC的请求状态
TimeCost(cnc);

//系统进入等待时间
if ((cnc[0].status1 == 0 && cnc[0].status2 == 0) && (cnc[1].status1 == 0 && cnc[1].status2 == 0) && (cnc[2].status1 == 0 && cnc[2].status2 == 0) && (cnc[3].status1 == 0 && cnc[3].status2 == 0) && (cnc[4].status1 == 0 && cnc[4].status2 == 0) && (cnc[5].status1 == 0 && cnc[5].status2 == 0) && (cnc[6].status1 == 0 && cnc[6].status2 == 0) && (cnc[7].status1 == 0 && cnc[7].status2 == 0))
{

Wait(cnc);

}
//选择下一个去的位置
else
{

route(cnc, &rgv);

}

}

//计算产出的总产品量
printf("总共生产了%d个熟料", n);

getchar();

return 0;
}

//判断某台CNC是否在加工产
void TimeCost(CNC k[8])
{
for (int r = 0;r < 8;r++)
{
if (abs((Time - k[r].T)) >= m)
{

k[r].status1 = 0;
k[r].status2 = 1;
}
}

}

void Pick1(CNC *k, int u)
{
k->status1 = 0;
k->status2 = 0;
U += u;//增加单位上下料时间
Time += u;

k->T = Time;//记录CNC开始工作时刻
//printf("%d\n", (k->T)-50);
}

void Pick2(CNC *k, int u)
{
int cc = random(101);
k->status1 = 0;
k->status2 = 0;
k->products++;
U += u;//增加单位上下料时间
Time += u;
if (cc == 10)
{
k->T = Time + random(10 * 60, 20 * 60) + random(0, m);
}
else{
k->T = Time;//记录CNC开始工作时刻
Q += q;//增加单位清洗时间
Time += q;
n++;
}

printf("%d\n", Time-50);
}

void Wait(CNC k[8]) {
int temp = 10000000;
for (int n = 0;n<8;n++)
{
if (temp >= k
.T)
{
temp = k
.T;
}
}
Time += (m - (Time - temp));//增加最小等待时间
}

void route(CNC k[8], RGV *s) {
int c = 5;
int d = 0;
for (int i = 0;i < 8;i++)
{
if (k[i].status1 == 1 || k[i].status2 == 1)
{
if (abs(k[i].Cp - s->RpNow)< c)
{

s->RpNext = k[i].Cp;
c = abs(s->RpNext - s->RpNow);
d = i;

}
/*
else
{
if (k[i].status2 == 1)    //pick2优先
{
s->RpNext = k[i].Cp;
c = abs(s->RpNext - s->RpNow);
d = i;
}
else
{
s->RpNext = k[i].Cp;
c = abs(s->RpNext - s->RpNow);
d = i - 1;

}

}
*/

}

}

//区别移动距离
if (c = 0)
h = 0;
else if (c = 1)
h = h1;
else if (c = 2)
h = h2;
else if (h = 3)
h = h3;

H =  h;
Time += h;
if (k[d].status2 == 1)  //判断CNC为奇还是偶
{
if (d % 2 == 0)
u = u2;
else if (d % 2 != 0)
u = u1;
Pick2(&k[d], u);

}
else if (k[d].status1 == 1)
{
if (d % 2 == 0)
u = u2;
else if (d % 2 != 0)
u = u1;
Pick1(&k[d], u);

}

s->RpNow = s->RpNext;//更新RGV位置
}
  • 两道工序
// mat.cpp: 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <math.h>
#include <ctime>
#define random(a,b) (rand()%(b-a)+a)
#define  knife1 4  //knife1和2决定了两种CNC的数量
#define  knife2 4
int m = 560,m1=280,m2=500;//CNC上单个产品加工时间

int Time = 0, H = 0, W = 0, U = 0, Q = 0; //Time为系统从开始到某时刻的时间;H为系统运动消耗时间;W为系统等待时间;U为系统上下料时间;Q为系统清洗熟料时间
int h = 0, w = 0,u=30, u1 = 28,u2=31, q = 30,h1=23,h2=41,h3=59;//u1为奇数CNC上下料时间,u2为偶数CNC上下料时间
int place1 = 1, place2 = 2, place3 = 3, place4 = 4;//设定RGV轨道上四个位置节点
int n = 0;//产出熟料数量

//构造两种CNC,一种装刀具1,一种装刀具2
class CNC1 {
public:
int T=0;
int status1=1;
int status2 = 0;
int Cp = place1;
int products = 0;
};

class CNC2 {
public:
int T = 10000000;
int status3 = 1;////////////////////////////////////////////////////////////////
int status4 = 0;
int Cp = place1;
int products = 0;
};

class RGV {
public :
int RpNow = place1;//RGV当前所处位置
int RpNext = place4;//RGV下一个遍历的位置
int hand = 0;
};

void TimeCost(CNC1 *k1,CNC2 *k2);
void Pick1(CNC1 *k,int u);
void Pick2(CNC1 *k,RGV *s,int u);
void Pick3(CNC2 *k,RGV *s,int u);
void Pick4(CNC2 *k,RGV *s,int u);
void Wait(CNC1 k1[knife1], CNC2 k2[knife2]);
//void route(CNC1 k1[knife1], CNC2 k2[knife2], RGV *s);
int None(CNC1 s1[knife1], CNC2 s2[knife2]);
int K2n( CNC2 s2[knife2],RGV k);
int K1n(CNC1 s1[knife1], RGV k);
int p1(CNC1 k[knife1]);
int p2(CNC1 k[knife1]);
int p3(CNC2 k[knife1]);
void step1(CNC1 k1[knife1], RGV *s);
void step2(CNC1 k1[knife1], RGV *s);
void step3(CNC2 k1[knife1], RGV *s);

int main()
{
RGV rgv;//一台RGV

CNC1 cnc1[knife1];
CNC2 cnc2[knife2];

if (knife1 == 3)
{
cnc1[0].Cp = place2, cnc1[1].Cp = place2, cnc1[2].Cp = place3;
cnc2[0].Cp = place1, cnc2[1].Cp = place1, cnc2[2].Cp = place3, cnc2[3].Cp = place4 , cnc2[4].Cp = place4;
}
else if(knife1 == 4)
{
cnc1[0].Cp = place1, cnc1[1].Cp = place2, cnc1[2].Cp = place3, cnc1[3].Cp = place4;
cnc2[0].Cp = place1, cnc2[1].Cp = place2, cnc2[2].Cp = place3, cnc2[3].Cp = place4;
}
else if(knife1==5)
{
cnc2[0].Cp = place2, cnc2[1].Cp = place2, cnc2[2].Cp = place3;
cnc1[0].Cp = place1, cnc1[1].Cp = place1, cnc1[2].Cp = place3, cnc1[3].Cp = place4, cnc1[4].Cp = place4;
}
else if(knife1==6)
{
cnc2[0].Cp = place2, cnc2[1].Cp = place3;
cnc1[0].Cp = place1, cnc1[1].Cp = place1, cnc1[2].Cp = place3, cnc1[3].Cp = place4, cnc1[4].Cp = place4 , cnc1[5].Cp = place2;
}

//RGV工作流程:

while (Time <= 8 * 3600)
{
//更新CNC的请求状态
TimeCost(cnc1, cnc2);
//系统进入等待时间
if (None(cnc1, cnc2)==0||K2n(cnc2,rgv)==0||K1n(cnc1,rgv)==0)
{

Wait(cnc1,cnc2);

}
//选择下一个去的位置
else
{

while (p1(cnc1))
{
step1(cnc1, &rgv);
}

if (rgv.hand == 0&&p2(cnc1)==1)
{
step2(cnc1, &rgv);
}
else if (rgv.hand == 1&&p3(cnc2)==1)
{
step3(cnc2, &rgv);
}

}

}

//计算产出的总产品量
printf("总共生产了%d个熟料", n);

getchar();

return 0;
}

//判断某台CNC是否加工完成产品
void TimeCost(CNC1 k1[knife1],CNC2 k2[knife2])
{
for (int r1 = 0;r1 < knife1;r1++)
{
if ((Time - k1[r1].T) >= m1)
{

k1[r1].status1 = 0;
k1[r1].status2 = 1;
}
}
for (int r2 = 0;r2 < knife2;r2++)
{
if ((Time - k2[r2].T) >= m2)
{

k2[r2].status3 = 0;
k2[r2].status4 = 1;
}
}

}

void Pick1(CNC1 *k, int u)
{
k->status1 = 0;
k->status2 = 0;
U += u;//增加单位上下料时间
Time += u;
k->T = Time;//记录CNC开始工作时刻
//printf("%d;\n", (k->T)-53);

}

void Pick2(CNC1 *k, RGV *s, int u)
{
k->status1 = 0;
k->status2 = 0;
s->hand = 1;//表示机械臂上已有一个半熟料
U += u;//增加单位上下料时间
Time += u;
k->T = Time;//记录CNC开始工作时刻
//printf("%d;%d\n",Time-53,(k->T)-u-53);
}

void Pick3(CNC2 *k, RGV *s , int u)
{
k->status3 = 0;
k->status4 = 0;
s->hand = 0;//表示机械臂上已经没有半熟料
U += u;//增加单位上下料时间
Time += u;
k->T = Time;//记录CNC开始工作时刻
printf("%d;\n", (k->T)-u-53);
}

void Pick4(CNC2 *k,RGV *s, int u)
{
k->status3 = 0;
k->status4 = 0;
s->hand = 0;
U += u;//增加单位上下料时间
Time += u;
k->T = Time;//记录CNC开始工作时刻
Q += q;
Time += q;
n++;
printf("%d;%d\n", Time - 53, (k->T) - u - 53);
}

void Wait(CNC1 k1[knife1],CNC2 k2[knife2]){  //取最小的pick2和最小的pick4,作比较取最小的那个最为等待时间
int temp1 = 10000000;
int temp2 = 10000000;
for (int n=0;n<knife1;n++)
{
if (temp1 >= k1
.T)
{
temp1 = k1
.T;
}
}
for (int n2 = 0;n2<knife2;n2++)
{
if (temp2 >= k2[n2].T)
{
temp2 = k2[n2].T;
}
}
if (temp1 > temp2)
{
Time += (m2 - (Time - temp2))+1;//增加最小等待时间
}
else
Time += (m1 - (Time - temp1))+1;//增加最小等待时间
}
/*
void route(CNC1 k1[knife1],CNC2 k2[knife2],RGV *s) {
int c = 5;
int c1 = 5;
int c2 = 5;
int d1 = 0;
int d2 = 0;

//找一个最近的CNC1,d1即为它的编号
for (int i = 0;i < knife1;i++)
{
if (k1[i].status1 == 1 || k1[i].status2 == 1)
{
if (abs(k1[i].Cp - s->RpNow)< c1)
{

s->RpNext = k1[i].Cp;
c1 = abs(s->RpNext -  s->RpNow);
d1 = i;

}
}

}

//找一个最近的CNC2,d2即为它的编号
for (int j = 0;j < knife2;j++)
{
if (k2[j].status3 == 1 || k2[j].status4 == 1)
{
if (abs(k2[j].Cp - s->RpNow)< c2)
{

s->RpNext = k2[j].Cp;
c2 = abs(s->RpNext - s->RpNow);
d2 = j;

}
}

}

//区别移动距离
if (c = 0)
h = 0;
else if (c = 1)
h = h1;
else if (c = 2)
h = h2;
else if (c = 3)
h = h3;

H +=  h;
Time +=  h;

if (k1[d1].status2 == 1)
{

if (d1 % 2 == 0)    //由于CNC编号与位置无关,无法判断CNC为奇还是偶
u = u2;
else if (d1 % 2 != 0)
u = u1;

Pick2(&k1[d1],s,u);

printf("编号为%d的CNC在时刻%ds完成熟料的下料以及生料的上料(pick2操作)\n", d1, Time);
}
else if(k1[d1].status1 == 1)
{
/*
if (d1 % 2 == 0)
u = u2;
else if (d1 % 2 != 0)
u = u1;

Pick1(&k1[d1],u);

printf("编号为%d的CNC在时刻%ds由待机状态放上生料开始工作(pick1操作)\n", d1, Time);

}

s->RpNow = s->RpNext;//更新RGV位置
}
*/

int None(CNC1 s1[knife1], CNC2 s2[knife2])  //如果没有任何指令返回0,否则返回1
{
int a = 0, b = 0;
for (int i = 0;i < knife1;i++)
{
if (s1[i].status1 != 0 || s1[i].status2 != 0)
{
a = 1;
break;
}
}
for (int j = 0;j < knife2;j++)
{
if (s2[j].status3 != 0 || s2[j].status4 != 0)
{
b = 1;
break;
}
}

if (a + b == 0)
return 0;
else
return 1;
}

int K2n( CNC2 s2[knife2],RGV k)//如果刀2无信号且机械臂上有一个半熟料则返回0
{
int a = 0;
for (int j = 0;j < knife2;j++)
{
if (s2[j].status3 != 0 || s2[j].status4 != 0 || k.hand != 1)
{
a = 1;
break;
}
}

return a;
}

int K1n(CNC1 s1[knife1], RGV k)
{
int a = 0;
for (int i = 0;i < knife1;i++)
{
if (s1[i].status1 != 0 || s1[i].status2 != 0||k.hand!=0)
{
a = 1;
break;
}
}

return a;
}

int p1(CNC1 k[knife1])//检验是否还有可执行的status1
{
int a=0;
for (int n = 0;n < knife1;n++)
{
if (k
.status1 == 0)
a += 0;
else
a += 1;
}

if (a == 0)
return 0;
else
return 1;
}

int p2(CNC1 k[knife1])//检验是否有可执行pick2的CNC1
{
int a = 0;
for (int n = 0;n < knife1;n++)
{
if (k
.status2 == 0)
a += 0;
else
a += 1;
}

if (a == 0)
return 0;
else
return 1;
}

int p3(CNC2 k[knife1])//检验是否有可执行pick3/pick4的CNC2
{
int a = 0;
for (int n = 0;n < knife1;n++)
{
if (k
.status3 == 0&&k
.status4==0)
a += 0;
else
a += 1;
}

if (a == 0)
return 0;
else
return 1;
}

void step1(CNC1 k1[knife1], RGV *s) //step1:找到最进的status1=1的CNC1
{
int c1 = 5;
int d1 = 0;
for (int i = 0;i < knife1;i++)
{
if (k1[i].status1 == 1)
{
if (abs(k1[i].Cp - s->RpNow)< c1)
{

s->RpNext = k1[i].Cp;
c1 = abs(s->RpNext - s->RpNow);
d1 = i;

}
}

}

//移动过去
if (c1 = 0)
h = 0;
else if (c1 = 1)
h = h1;
else if (c1 = 2)
h = h2;
else if (c1 = 3)
h = h3;
H += h;
Time += h;

//完成pick1
Pick1(&k1[d1], u);
//printf("编号为%d的CNC1在%d时刻完成pick1\n",d1,Time);
s->RpNow = s->RpNext;//更新RGV位置
}

void step2(CNC1 k1[knife1],RGV *s) //step2:找到最进的能执行pick2的CNC1
{
int c1 = 5;
int d1 = 0;
for (int i = 0;i < knife1;i++)
{
if (k1[i].status2 == 1 )
{
if (abs(k1[i].Cp - s->RpNow)< c1)
{

s->RpNext = k1[i].Cp;
c1 = abs(s->RpNext - s->RpNow);
d1 = i;

}
}

}

//移动过去
if (c1 = 0)
h = 0;
else if (c1 = 1)
h = h1;
else if (c1 = 2)
h = h2;
else if (c1 = 3)
h = h3;
H += h;
Time += h;

//完成pick2
Pick2(&k1[d1],s, u);
//printf("编号为%d的CNC1在%d时刻完成pick2\n", d1, Time);
s->RpNow = s->RpNext;//更新RGV位置
}

void step3(CNC2 k1[knife1], RGV *s)
{
int c1 = 5;
int d1 = 0;
for (int i = 0;i < knife1;i++)   //找一个最近的能执行pick3或pick4的CNC2
{
if (k1[i].status3 == 1||k1[i].status4==1)
{
if (abs(k1[i].Cp - s->RpNow)< c1)
{

s->RpNext = k1[i].Cp;
c1 = abs(s->RpNext - s->RpNow);
d1 = i;

}
}

}

//移动过去
if (c1 = 0)
h = 0;
else if (c1 = 1)
h = h1;
else if (c1 = 2)
h = h2;
else if (c1 = 3)
h = h3;
H += h;
Time += h;

//完成pick3或pick4
if (k1[d1].status3 == 1)
{
Pick3(&k1[d1], s, u);
//printf("编号为%d的CNC2在%d时刻完成pick3\n", d1, Time);
}
else if (k1[d1].status4 == 1)
{
Pick4(&k1[d1], s, u);
//printf("编号为%d的CNC2在%d时刻完成pick4\n", d1, Time);
}

s->RpNow = s->RpNext;//更新RGV位置
}
  • 点赞 1
  • 收藏
  • 分享
  • 文章举报
喜飏飏 发布了2 篇原创文章 · 获赞 1 · 访问量 79 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: