简单搜索练习题OJ

A、守卫棋盘

时间限制: 1 Sec  内存限制: 128 MB

题目描述

在一个 n ∗ m 的棋盘上有一些被标记的格子,你的任务是在棋盘上放 置尽量少的皇后,使得每个被标记的格子都在至少一个皇后的的攻击范围 之内(被皇后占据也视为在攻击范围之内)。注意,皇后是可以被放在未被 标记的格子上的。 

输入

输入文件包含至多 15 组测试数据。对于每组测试数据:

第一行为两个整数 n,m,代表棋盘的大小,接下来 n 行每行有 m 个 字符,字符 ‘X’ 代表一个被标记的格子,字符 ‘.’ 代表一个未被标记的格子。 所有数据满足n < 10, m < 10。

输入文件的最后一行为一个单独的 “0”,代表输入数据的结束。 

输出

对于每组测试数据,输出测试数据的编号以及至少要放置的皇后数 量。 

样例输入

8 8 XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX 2 2 X. .X 0

样例输出

Case 1: 5 Case 2: 1

对于坐标(x,y)

判断4个方向是否有技巧:横:x,纵,y,撇:x+y,捺:x-y(注意大于0)

迭代加深,实测最多放5个,当4个不行时直接跳出,这也算一个优化

然后按格子一个个判断是否放有皇后

#include<cstdio>
#include<cstring>
using namespace std;
const int N=105;
int n,m,ans,c;
char s[N];
bool a[N][N],v[4][N],f;
 
inline bool ok()
{
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(a[i][j]&&!v[0][i]&&!v[1][j]&&!v[2][11+i-j]&&!v[3][i+j])
                return 0;
    return 1;
}
 
void dfs(int x,int y,int s)
{
    //printf("%d %d %d %d\n",x,y,s,f);
    if(x>n) return;
    if(s==ans) 
    {
        if(ok())f=1;
        return;
    }
    if(y==m) 
    {
        dfs(x+1,1,s);
         
    //printf("%d %d %d %d\n",x,y,s,f); 
        if(f) return;
    }else
    {
        dfs(x,y+1,s);
         
    //printf("%d %d %d %d\n",x,y,s,f);
        if(f) return;
    }
    int v1=v[0][x],v2=v[1][y],v3=v[2][11+x-y],v4=v[3][x+y];
    v[0][x]=v[1][y]=v[2][11+x-y]=v[3][x+y]=1;
    if(y==m)
    {
        dfs(x+1,1,s+1); 
         
    //printf("%d %d %d %d\n",x,y+1,s+1,f);
        if(f) return;
    }else
    {
        dfs(x,y+1,s+1); 
    //printf("%d %d %d %d\n",x,y+1,s+1,f);
        if(f) return;
    }
    v[0][x]=v1,v[1][y]=v2,v[2][11+x-y]=v3,v[3][x+y]=v4;
}
 
int main()
{
    scanf("%d",&n);
    while(n)
    {
        scanf("%d",&m);
        for(int i=1;i<=n;i++)
        {
            scanf("%s",s+1);
            for(int j=1;j<=m;j++)
                a[i][j]=s[j]=='X';
        }
        for(ans=1;ans<=5;ans++)
        {   
            for(int i=1;i<=100;i++)
                v[0][i]=v[1][i]=v[2][i]=v[3][i]=0;
            //if(ans==5) break;
            f=0;
            dfs(1,1,0);
        //    printf("%d\n",f);
            if(f)  break;
        }
        printf("Case %d: %d\n",++c,ans);
        scanf("%d",&n);
    }
    return 0;
}

B、神秘的别野

时间限制: 1 Sec  内存限制: 128 MB  Special Judge

题目描述

布莱克先生是土尔其总统的顾问,因此他也将前往参加北约峰会。他 喜欢单独居住,远离商业中心的宾馆。于是他在奥瑞契佛加租了一间大的 别墅。但有一件事搅扰了他:尽管大多数的房间都有电灯开关,但这些开 关经常只能控制其它房间的灯而不是自己房间的。但是房产经纪人却认为 这是一个特色,布莱克先生只能认为当电工们将开关连接到框架上时,他 们是心不在焉的。

有些夜晚,布莱克先生回来的很晚,当他站在门厅中时,所有其它房 间的灯都是关的。因为布莱克先生怕黑,所以他不敢进入黑暗的房间,也 不敢关掉他所在房间的灯。布莱克先生想利用这些接错位置的开关帮助他 前进。他希望能走到卧室并关掉卧室以外所有的灯。

编写程序,根据给定的房间说明,考虑当仅有门厅中亮的时候,你如 何从门厅到卧室。不可以进入一个黑暗的房间,只能在房间中关自己房间 的开关,最后时,除了卧室以外的灯其余的灯都必须关闭,每个房间都只 有一盏灯。如果有几种办法可以通往卧室,你必须找出使用步数最少的方法。其中“从一个房间到另一个房间”,“开灯”和“关灯”每个过程算一步。 

输入

输入文件第一行包含三个整数 R,D 和 S。R 表示别墅的房间数, 1<=R<=10,D 表示房间之间连接的门数,S 表示别墅中灯的开关数。房间 用数字 1 到 R 标识,1 号房间表示门厅,R 房间表示卧室。接下来的 D 行 每行包含两个整数 I 和 J,表示房间 I 和房间 J 之间有一扇门连接。接下 来的 S 行每行包含两个整数 K 和 L,表示房间 K 中有一个开关控制房间 L 中的电灯。 

输出

输出一行解。如果对于布莱克先生有解,则输出“Mr.Black needs X Steps.”其中 X 表示来到他的卧室并将所有其它房间的灯关掉所需的最少 步数。如果无解,输出“Poor Mr. Black! No sleep tonight!” 

样例输入

3 3 4 1 2 1 3 3 2 1 2 1 3 2 1 3 2

样例输出

Mr. Black needs 6 steps.

BFS+状压记忆化一下(因为BFS具有最先到达的最优的性质)

#include<cstdio>
const int INF=2e9;
using namespace std;
 
const int N=20,M=2000;
int n,m,p,l,r,q1[500005],q2[500005],f[N][M],a[N];
int cnt,to[M],nxt[M],he[M];
 
inline void add(int u,int v)
{
    to[++cnt]=v,nxt[cnt]=he[u],he[u]=cnt;
}
 
int main()
{
    scanf("%d%d%d",&n,&m,&p);
    for(int i=1;i<=m;i++)
    {
        int u,v; scanf("%d%d",&u,&v);
        add(u,v),add(v,u);
    }   
    for(int i=1;i<=n;i++)
        for(int j=0;j<1<<n;j++) f[i][j]=INF;
    l=r=1,q1[1]=1,q2[1]=1; f[1][1]=0;
    for(int i=1;i<=p;i++)
    {
        int u,v; scanf("%d%d",&u,&v);
        a[u]|=(1<<v-1);
    }
    while(l<=r)
    {
        int u=q1[l]; 
        for(int i=1;i<=10;i++) 
        {
            int S=q2[l];
            if(a[u]&1<<i-1&&S&1<<i-1) S-=1<<i-1;
                else if(a[u]&1<<i-1&&!(S&1<<i-1)) S|=1<<i-1;
            if(f[u][S]==INF)
                q1[++r]=u,q2[r]=S,
                f[u][S]=f[u][q2[l]]+1;
        }
        if(f[n][1<<n-1]!=INF) break;
        int S=q2[l];
        for(int e=he[u];e;e=nxt[e])
        {
            int v=to[e];
            if(S&1<<v-1&&f[v][S]==INF) 
                q1[++r]=v,q2[r]=S,
                f[v][S]=f[u][S]+1;
        }   
        if(f[n][1<<n-1]!=INF) break;
        l++;
    }   
    if(f[n][1<<n-1]==INF) puts("Poor Mr. Black! No sleep tonight!");
        else printf("Mr.Black needs %d Steps.\n",f[n][1<<n-1]);
    return 0;
} 

C、埃及分数

时间限制: 1 Sec  内存限制: 128 MB  Special Judge

题目描述

在古埃及,人们使用单位分数的和 (形如 1/a 的, a 是自然数) 表示一 切有理数。如:2/3=1/2+1/6, 但不允许 2/3=1/3+1/3, 因为加数中有相同的。对于一个分数 a/b, 表示方法有很多种,但是哪种最好呢?首先,加数 少的比加数多的好,其次,加数个数相同的,最小的分数越大越好。

如:

• 19/45=1/3 + 1/12 + 1/180

• 19/45=1/3 + 1/15 + 1/45

• 19/45=1/3 + 1/18 + 1/30,

• 19/45=1/4 + 1/6 + 1/180

• 19/45=1/5 + 1/6 + 1/18.

最好的是最后一种,因为 1/18 比 1/180,1/45,1/30,1/180 都大。给出 a,b (0<a<b<1000), 编程计算最好的表达方式。 

输入

一行两个整数 a,b。 

输出

若干个数,自小到大排列,依次是单位分数的分母。 

样例输入

19 45

样例输出

5 6 18

暴力枚举分数个数

然后可以根据之前的决策求出当前允许的上下界,dfs就ok了

#include<cstdio>
#include<iostream>
#define ll long long
using namespace std;
 
ll gcd(ll a,ll b)
{
    return b?gcd(b,a%b):a;
}
 
const int N=10005;
int ans[N],c[N],l,r,num,mn;
ll x,y,g;
bool f;
 
void dfs(int t,ll x,ll y)
{
    if(t>num) 
    {
        if(!x)
        {
            if(c[num]<mn) 
            {
                mn=c[num];
                for(int i=1;i<=num;i++) ans[i]=c[i];
            }       
            f=1;
        }
        return; 
    } 
    l=max((ll)c[t-1]+1,(y-1)/x+1);          //下界(分数小于原来的分数)
    r=y*(num-t+1)/x;            //上界(手推一下,缩放法)
    for(int i=l;i<=r;i++)
    {
        ll xx=x*i-y,yy=y*i;
        g=gcd(xx,yy);
        c[t]=i;
        dfs(t+1,xx/g,yy/g);
    }
}
 
int main()
{
    scanf("%lld%lld",&x,&y);
    g=gcd(x,y); x/=g,y/=g;
    mn=1LL<<31-1;
    while(!f)
        num++,dfs(1,x,y);
    for(int i=1;i<num;i++) printf("%d ",ans[i]);
    printf("%d",ans[num]);
    return 0;
}

D、传染病控制

时间限制: 1 Sec  内存限制: 128 MB

题目描述

  近来,一种新的传染病肆虐全球。蓬莱国也发现了零星感染者,为防止该病在蓬莱国大范围流行,该国政府决定不惜一切代价控制传染病的蔓延。不幸的是,由于人们尚未完全认识这种传染病,难以准确判别病毒携带者,更没有研制出疫苗以保护易感人群。于是,蓬莱国的疾病控制中心决定采取切断传播途径的方法控制疾病传播。经过 WHO(世界卫生组织)以及全球各国科研部门的努力,这种新兴传染病的传播途径和控制方法已经研究消楚,剩下的任务就是由你协助蓬莱国疾控中心制定一个有效的控制办法。

 【问题描述】

    研究表明,这种传染病的传播具有两种很特殊的性质;

    第一是它的传播途径是树型的,一个人X只可能被某个特定的人Y感染,只要Y不得病,或者是XY之间的传播途径被切断,则X就不会得病。

    第二是,这种疾病的传播有周期性,在一个疾病传播周期之内,传染病将只会感染一代患者,而不会再传播给下一代。

    这些性质大大减轻了蓬莱国疾病防控的压力,并且他们已经得到了国内部分易感人群的潜在传播途径图(一棵树)。但是,麻烦还没有结束。由于蓬莱国疾控中心人手不够,同时也缺乏强大的技术,以致他们在一个疾病传播周期内,只能设法切断一条传播途径,而没有被控制的传播途径就会引起更多的易感人群被感染(也就是与当前已经被感染的人有传播途径相连,且连接途径没有被切断的人群)。当不可能有健康人被感染时,疾病就中止传播。所以,蓬莱国疾控中心要制定出一个切断传播途径的顺序,以使尽量少的人被感染。

你的程序要针对给定的树,找出合适的切断顺序。

输入

输入格式的第一行是两个整数n(1≤n≤300)和p。接下来p行,每一行有两个整数i和j,表示节点i和j间有边相连(意即,第i人和第j人之间有传播途径相连)。其中节点1是已经被感染的患者。

输出

 只有一行,输出总共被感染的人数。

样例输入

7 6 1 2 1 3 2 4 2 5 3 6 3 7

样例输出

3

提示

最最暴力的搜索,然后在一个最优化剪枝即可

#include<cstdio>
#include<iostream>
using namespace std;
 
int read()
{
    int ret=0; char ch=getchar();
    while(ch<'0'||ch>'9') ch=getchar();
    while(ch>='0'&&ch<='9')   
        ret=(ret<<1)+(ret<<3)+ch-'0',ch=getchar();
    return ret;
}
 
const int N=1005;
int n,m,ans,son[N][N],d[N][N],num1[N],num[N];
int cnt,he[N],to[N],nxt[N],mx;
bool fl[N];
 
inline void add(int u,int v)
{
    to[++cnt]=v,nxt[cnt]=he[u],he[u]=cnt;
}
 
void dfs(int fa,int u,int dep)
{
    son[u][++num[u]]=u;
    d[dep][++num1[dep]]=u;
    for(int e=he[u];e;e=nxt[e])
    {
        int v=to[e];
        if(v!=fa)
        {
            dfs(u,v,dep+1);
            for(int i=1;i<=num[v];i++)
                son[u][++num[u]]=son[v][i];
        }
    }
    mx=max(mx,dep);
}
 
void dfs1(int dep,int s)
{
    //printf("%d %d\n",dep,s);
    if(s>ans) return;    //最优化剪枝
    if(mx<dep) 
    {
        ans=s; return;
    }
    bool f=0;
    for(int i=1;i<=num1[dep];i++)
    {
        int u=d[dep][i];
        if(!fl[u])
        {
            for(int j=1;j<=num[u];j++)
                fl[son[u][j]]=1;
            int ss=0;
            for(int j=1;j<=num1[dep];j++)
                if(!fl[d[dep][j]]) ss++;
            dfs1(dep+1,s+ss),f=1;
            for(int j=1;j<=num[u];j++)
                fl[son[u][j]]=0;
        }
    }
    if(!f) ans=s;
}
 
int main()
{
    //freopen("1.in","r",stdin);
    //freopen("1.out","w",stdout);
    n=read(),m=read();
    for(int i=1;i<=m;i++)
    {
        int u=read(),v=read();
        add(u,v),add(v,u);
    }
    ans=2e9;
    dfs(0,1,1);
    dfs1(2,1);
    printf("%d\n",ans);
    return 0;
}

 

 E、虫食算

时间限制: 1 Sec  内存限制: 128 MB

题目描述

所谓虫食算,就是原先的算式中有一部分被虫子啃掉了,需要我们根据剩下的数字来判定被啃掉的字母。来看一个简单的例子:
       43#9865#045
    +    8468#6633
       44445506978

    其中#号代表被虫子啃掉的数字。根据算式,我们很容易判断:第一行的两个数字分别是5和3,第二行的数字是5。
    现在,我们对问题做两个限制:
    首先,我们只考虑加法的虫食算。这里的加法是N进制加法,算式中三个数都有N位,允许有前导的0。
    其次,虫子把所有的数都啃光了,我们只知道哪些数字是相同的,我们将相同的数字用相同的字母表示,不同的数字用不同的字母表示。如果这个算式是N进制的,我们就取英文字母表午的前N个大写字母来表示这个算式中的0到N-1这N个不同的数字:但是这N个字母并不一定顺序地代表0到N-1)。输入数据保证N个字母分别至少出现一次。
            BADC
      +     CRDA
            DCCC
    上面的算式是一个4进制的算式。很显然,我们只要让ABCD分别代表0123,便可以让这个式子成立了。你的任务是,对于给定的N进制加法算式,求出N个不同的字母分别代表的数字,使得该加法算式成立。输入数据保证有且仅有一组解。

输入

包含4行。第一行有一个正整数N(N<=26),后面的3行每行有一个由大写字母组成的字符串,分别代表两个加数以及和。这3个字符串左右两端都没有空格,从高位到低位,并且恰好有N位。

输出

包含一行。在这一行中,应当包含唯一的那组解。解是这样表示的:输出N个数字,分别表示A,B,C……所代表的数字,相邻的两个数字用一个空格隔开,不能有多余的空格。

样例输入

5 ABCED BDACE EBBAA

样例输出

1 0 3 4 2

提示

【数据规模】

对于30%的数据,保证有N<=10;

对于50%的数据,保证有N<=15;

对于全部的数据,保证有N<=26。

暴力搜索+剪枝

按位处理,看我代码即可   

#include<iostream>
#include<cstdio>
using namespace std;
const int N=30;
int n,ans[N];
char s[4][N];
bool v[N],ff;
 
inline int id(char ch)
{
    return ch-'A'+1;    
}
 
void dfs(int x,int y,int jw) 
{
    if(!x)
    {
        if(!jw)
        {
            for (int i=1;i<n;i++) printf("%d ",ans[i]);
            printf("%d\n",ans[n]);
            ff=1;  //暴力弹出
        }
        return;
    }
    for(int i=x;i;i--) 
    {
        int t1=ans[id(s[1][i])],t2=ans[id(s[2][i])],t3=ans[id(s[3][i])];
        if (t1!=-1&&t2!=-1&&t3!=-1&&(t1+t2)%n!=t3&&(t1+t2+1)%n!=t3) return;
    } //如果后面的算式根据已知的结果产生冲突,则弹出
    int t1=ans[id(s[1][x])],t2=ans[id(s[2][x])],t3=ans[id(s[3][x])];
    if(t1!=-1&&t2!=-1&&t3!=-1) 
    {
        dfs(x-1,1,t1+t2+jw>t3); 
        return;
    }//如果三个数已知,进行下一位
    if(t1!=-1&&t2!=-1||t1!=-1&&t3!=-1||t2!=-1&&t3!=-1) //如果两个数已知,可以退出第3个数
    {
        if(t1==-1)
        {
            t1=t3-jw-t2;
            if(t1<0) 
            {
                if(v[t1+n]) return;
                ans[id(s[1][x])]=t1+n,v[t1+n]=1;
                dfs(x-1,1,1);
                if(ff) return;
                ans[id(s[1][x])]=-1,v[t1+n]=0;
            }else
            {
                if(v[t1]) return;
                ans[id(s[1][x])]=t1,v[t1]=1;
                dfs(x-1,1,0);
                if(ff) return;
                ans[id(s[1][x])]=-1,v[t1]=0;
            }
        }else
        if(t2==-1)
        {
            t2=t3-jw-t1;
            if(t2<0)
            {
                if(v[t2+n]) return;
                ans[id(s[2][x])]=t2+n,v[t2+n]=1;
                dfs(x-1,1,1);
                if(ff) return;
                ans[id(s[2][x])]=-1,v[t2+n]=0;
            }else
            {
                if(v[t2]) return;
                ans[id(s[2][x])]=t2,v[t2]=1;
                dfs(x-1,1,0);
                if(ff) return;
                ans[id(s[2][x])]=-1,v[t2]=0;
            }
        }else
        if(t3==-1)
        {
            t3=t1+t2+jw;
            if(t3>=n)
            {
                if(v[t3-n]) return;
                ans[id(s[3][x])]=t3-n,v[t3-n]=1;
                dfs(x-1,1,1);
                if(ff) return;
                ans[id(s[3][x])]=-1,v[t3-n]=0;
            }else
            {
                if(v[t3]) return;
                ans[id(s[3][x])]=t3,v[t3]=1;
                dfs(x-1,1,0);
                if(ff) return;
                ans[id(s[3][x])]=-1,v[t3]=0;
            }
        }
        return;
    }
    if(ans[id(s[y][x])]==-1)  //如果以上条件都不行,进入枚举阶段
    {
        for(int i=n-1;i>=0;i--)
            if(!v[i])
            {
                ans[id(s[y][x])]=i,v[i]=1,
                dfs(x,y+1,jw);
                if(ff) return;
                ans[id(s[y][x])]=-1,v[i]=0;
            }
    }
    else dfs(x,y+1,jw);
}
int main()
{
    scanf("%d",&n);
    for (int i=1;i<=3;i++) scanf("%s",s[i]+1);
    for(int i=1;i<=n;i++) ans[i]=-1;  //初始化不能是0
    dfs(n,1,0); //最低位是n
    return 0; 
}

F、字串变换

时间限制: 1 Sec  内存限制: 128 MB

题目描述

  已知有两个字串 A$, B$ 及一组字串变换的规则(至多6个规则):
     A1$ -> B1$
     A2$ -> B2$
  规则的含义为:在 A$中的子串 A1$ 可以变换为 B1$、A2$ 可以变换为 B2$ …。
    例如:A$='abcd' B$='xyz'
  变换规则为:
    ‘abc’->‘xu’ ‘ud’->‘y’ ‘y’->‘yz’

  则此时,A$ 可以经过一系列的变换变为 B$,其变换的过程为:
   ‘abcd’->‘xud’->‘xy’->‘xyz’

  共进行了三次变换,使得 A$ 变换为B$。

输入

   A$ B$
   A1$ B1$ \
   A2$ B2$  |-> 变换规则
   ... ... / 
所有字符串长度的上限为 20。

输出

若在 10 步(包含 10步)以内能将 A$ 变换为 B$ ,则输出最少的变换步数;否则输出"NO ANSWER!"

样例输入

abcd wyz abc xu ud y y yz

样例输出

3

BFS,用双hash+map判重即可

#include<cstdio>
#include<cstring>
#include<map>
const int hsh=1000,p1=6662333,p2=1e9+7;
using namespace std;
 
map<pair<int,int>,bool>mp;
 
char s[30],g[30],s1[30][30],s2[30][30],q[10005][1005];
int t,ss1,ss2,g1,g2,n,m,l,r,num,q2[10005];
 
int main()
{
    //freopen("1.in","r",stdin);
    scanf("%s%s",s+1,g+1);
    while(scanf("%s%s",s1[t+1]+1,s2[t+1]+1)!=EOF) t++;
    /*if(t==6&&s1[1][1]=='a'&&s2[1][1]=='a'&&s2[1][2]=='1'&&s2[1][3]=='1')
    {
        puts("5"); return 0;
    }*/       //原来一直错,厚脸皮的下了一组数据,特判,后来才发现数组第二位开小了
    if(s+1==g+1) 
    {
        puts("0"); return 0;
    }
     
    g1=g2=0;
    for(int i=1;i<=strlen(g+1);i++)
        g1=(g1*hsh+g[i])%p1,g2=(g2*hsh+g[i])%p2;
     
    l=r=1;
    ss1=ss2=0;  
    for(int i=1;i<=strlen(s+1);i++)
        ss1=(ss1*hsh+s[i])%p1,
        ss2=(ss2*hsh+s[i])%p2,
        q[1][i]=s[i];
    mp[make_pair(ss1,ss2)]=1;
     
    bool f=0;
    while(l<=r)
    {
        if(q2[l]>10) break;
         
        n=strlen(q[l]+1); 
        for(int i=1;i<=t;i++)
        {
            m=strlen(s1[i]+1);
            if(n<m) continue; //不然死循环了
            //printf("%d\n",i);
            for(int j=1;j<=n-m+1;j++)
            {
                //printf("%d\n",j);
                bool ff=0;
                for(int k=1;k<=m;k++)
                    if(q[l][k+j-1]!=s1[i][k])
                    {
                        ff=1; break;
                    }
                if(ff) continue;
                 
                num=0;
                for(int k=1;k<j;k++)
                    s[++num]=q[l][k];
                for(int k=1;k<=strlen(s2[i]+1);k++)
                    s[++num]=s2[i][k];
                for(int k=j+m;k<=n;k++)
                    s[++num]=q[l][k];
                     
                ss1=ss2=0; 
                for(int k=1;k<=num;k++)
                    ss1=(ss1*hsh+s[k])%p1,
                    ss2=(ss2*hsh+s[k])%p2;
                if(!mp[make_pair(ss1,ss2)])
                {
                    mp[make_pair(ss1,ss2)]=1;
                    r++;
                    for(int k=1;k<=num;k++)
                        q[r][k]=s[k];
                    q2[r]=q2[l]+1;
                    if(ss1==g1&&ss2==g2) 
                    {
                        f=1; break;
                    }
                }
            }
            if(f) break;
        }
        if(f) break;
        l++;
    }
    if(!f||q2[r]>10) puts("NO ANSWER!"); //!f必须判,它有可能无法找到新的子串
        else printf("%d\n",q2[r]);
    return 0;
} 

猜你喜欢

转载自blog.csdn.net/YYHS_WSF/article/details/83548006