PTA天梯决赛14题直捣黄龙
2017-03-23 13:53
190 查看
题目:
5-14 直捣黄龙 (30分)
本题是一部战争大片 —— 你需要从己方大本营出发,一路攻城略地杀到敌方大本营。首先时间就是生命,所以你必须选择合适的路径,以最快的速度占领敌方大本营。当这样的路径不唯一时,要求选择可以沿途解放最多城镇的路径。若这样的路径也不唯一,则选择可以有效杀伤最多敌军的路径。
≤\le≤
200,城镇总数)和
简要分析:这个题目个人感觉就是枚举各种路线的走法,然后把满足条件的路线和最优路线给记录下来,说起来好像很简单(笑哭)确实对大牛来说也是很简单的,可是作为一只萌新,我可花了不少时间呐,唉,好了不闲聊了,讲正事。
思路:由于要考虑每一条路线,即把每一条路线都给走一遍,所以我们需要回溯(我只能想到这种办法TAT)还有图。主要思路理清了这题也不是特别难,总共就两个思想嘛(写了那么久还好意思说),接下来呈上代码,有可以优化的建议的话请大佬们提出呦。
代码:
#include<stdio.h>
#include<stdlib.h>
struct cityi //城市数据
{
int arrive_; //可以进入的城市的数目
struct a
{
int cityid; //可以进入的城市
int distance; //去这个城市所需要的距离
}arrive[199+20]; //由于城市上限不超过200个,所以我们就算所有城市都能去也只有199条路。
int enemy;
}citys[199+20]; //同上,不超过200个城市。
int symbol[201]={0}; //标记,如果走过的城市在同一条路线里不会走第二次,因为我们要最快速度最短距离。
int rails=0; //最短距离的路的条数。
int railway[201]; //记录路线
int truerailway[201]; //最终最优路线
int railway_=0; //当前经过的城市的个数
int truerailways=-1; //最优路线经过城市的个数
char cityname[201][4]; //代号转换,将名字转换成数字,后面的conversion函数就是转换功能。
int maxkill=-1; //最优路线歼敌数
int mixdistance=500000; //最短进攻距离
int maxtown=-1; //最优路线解放的城镇的数目
int conversion(char name[4],int N); //城镇代号与数字之间的转化
int compare(char name1[4],char name2[4]); //比较城镇是否相同
void seek(int now ,int distance,int kill,int town);
int main()
{
int N,K;
char wgzf;
int amount;
scanf("%d%d",&N,&K);
scanf("%c",&wgzf);
scanf("%s",cityname[0]);
scanf("%s",cityname[1]);
citys[0].arrive_=0; //初始化第一个城镇(即我方大本营)
citys[0].enemy=0; //我方大本营没有敌军
amount=N-1; //题目要求N-1条路线
int cityname_=2; //已经初始化了两个城镇,所以从第三个城镇开始计数
while(amount--) //输入,并初始化所有城镇注意由于先前只输入一个敌方大本营,并没有输入敌人人数。
{
int number;
scanf("%s",cityname[cityname_]);
scanf("%d",&number);
if(compare(cityname[1],cityname[cityname_])) //判断是否为敌方大本营,是的话初始化敌人个数
{
citys
b1b3
[1].enemy=number;
citys[1].arrive_=0;
}
else
{
citys[cityname_].enemy=number;
citys[cityname_].arrive_=0;
cityname_++;
}
}
while(K--) //输入路线以及距离(注意两个城镇都要初始化)
{
char name1[4];
char name2[4];
int distance;
scanf("%s",name1);
scanf("%s",name2);
scanf("%d",&distance);
int id1,id2;
id1=conversion(name1,N);
id2=conversion(name2,N);
citys[id1].arrive[citys[id1].arrive_].cityid=id2;
citys[id1].arrive[citys[id1].arrive_++].distance=distance;
citys[id2].arrive[citys[id2].arrive_].cityid=id1;
citys[id2].arrive[citys[id2].arrive_++].distance=distance;
}
int times; //标记大本营
symbol[0]=1;
seek(0,0,0,0);
int hh;
printf("%s",cityname[0]);
for(hh=0;hh<truerailways;hh++)
printf("->%s",cityname[truerailway[hh]]);
printf("\n");
printf("%d %d %d",rails,mixdistance,maxkill);
}
int compare(char name1[4],char name2[4]) //比较函数
{
char *p1,*p2;
p1=name1;
p2=name2;
while(*p1==*p2 && *p1!='\0')
{
p1++;
p2++;
}
if(*p1=='\0')
return 1;
else
return 0;
}
int conversion(char name[4],int N) //转换函数,转换城镇代号
{
int i;
for(i=0;i<N;i++)
if(compare(cityname[i],name))
return i;
return -1;
}
void seek(int now ,int distance,int kill,int town) //查询函数,枚举回溯每一条路线
{
kill+=citys[now].enemy;
if(now==1) //终止条件,由于先前定义地方大本营位置为1
{
if(distance<=mixdistance) //是最短距离的时候进行考虑否则直接跳过
{
if(distance<mixdistance)
{
rails=0; //若是新的最短距离,更新最优路线数量
mixdistance=distance;
maxtown=town;
maxkill=kill;
truerailways=railway_;
int times;
for(times=0;times<railway_;times++) //记录最优路线
truerailway[times]=railway[times];
}
else
if(town>=maxtown)
{
if(town>maxtown)
{
maxtown=town;
maxkill=kill;
truerailways=railway_;
int times;
for(times=0;times<railway_;times++) //记录最优路线
truerailway[times]=railway[times];
}
else
if(kill>maxkill)
{
maxkill=kill;
truerailways=railway_;
int times;
for(times=0;times<railway_;times++) //记录最优路线
truerailway[times]=railway[times];
}
}
rails++;
}
return ;
}
int i;
for(i=0;i<citys[now].arrive_;i++) //回溯
{
if(symbol[citys[now].arrive[i].cityid]==0) //判断是否已被标记
{
railway[railway_++]=citys[now].arrive[i].cityid; //记录当前路线
symbol[citys[now].arrive[i].cityid]=1;
seek(citys[now].arrive[i].cityid,distance+citys[now].arrive[i].distance,kill,town+1);
symbol[citys[now].arrive[i].cityid]=0; //
railway_--; //返回初始状态
}
}
}
5-14 直捣黄龙 (30分)
本题是一部战争大片 —— 你需要从己方大本营出发,一路攻城略地杀到敌方大本营。首先时间就是生命,所以你必须选择合适的路径,以最快的速度占领敌方大本营。当这样的路径不唯一时,要求选择可以沿途解放最多城镇的路径。若这样的路径也不唯一,则选择可以有效杀伤最多敌军的路径。
输入格式:
输入第一行给出2个正整数N(2 ≤\le≤
N
≤\le≤
200,城镇总数)和
K(城镇间道路条数),以及己方大本营和敌方大本营的代号。随后
N-1行,每行给出除了己方大本营外的一个城镇的代号和驻守的敌军数量,其间以空格分隔。再后面有
K行,每行按格式
城镇1 城镇2 距离给出两个城镇之间道路的长度。这里设每个城镇(包括双方大本营)的代号是由3个大写英文字母组成的字符串。
输出格式:
按照题目要求找到最合适的进攻路径(题目保证速度最快、解放最多、杀伤最强的路径是唯一的),并在第一行按照格式己方大本营->城镇1->...->敌方大本营输出。第二行顺序输出最快进攻路径的条数、最短进攻距离、歼敌总数,其间以1个空格分隔,行首尾不得有多余空格。
输入样例:
10 12 PAT DBY DBY 100 PTA 20 PDS 90 PMS 40 TAP 50 ATP 200 LNN 80 LAO 30 LON 70 PAT PTA 10 PAT PMS 10 PAT ATP 20 PAT LNN 10 LNN LAO 10 LAO LON 10 LON DBY 10 PMS TAP 10 TAP DBY 10 DBY PDS 10 PDS PTA 10 DBY ATP 10
输出样例:
PAT->PTA->PDS->DBY 3 30 210
简要分析:这个题目个人感觉就是枚举各种路线的走法,然后把满足条件的路线和最优路线给记录下来,说起来好像很简单(笑哭)确实对大牛来说也是很简单的,可是作为一只萌新,我可花了不少时间呐,唉,好了不闲聊了,讲正事。
思路:由于要考虑每一条路线,即把每一条路线都给走一遍,所以我们需要回溯(我只能想到这种办法TAT)还有图。主要思路理清了这题也不是特别难,总共就两个思想嘛(写了那么久还好意思说),接下来呈上代码,有可以优化的建议的话请大佬们提出呦。
代码:
#include<stdio.h>
#include<stdlib.h>
struct cityi //城市数据
{
int arrive_; //可以进入的城市的数目
struct a
{
int cityid; //可以进入的城市
int distance; //去这个城市所需要的距离
}arrive[199+20]; //由于城市上限不超过200个,所以我们就算所有城市都能去也只有199条路。
int enemy;
}citys[199+20]; //同上,不超过200个城市。
int symbol[201]={0}; //标记,如果走过的城市在同一条路线里不会走第二次,因为我们要最快速度最短距离。
int rails=0; //最短距离的路的条数。
int railway[201]; //记录路线
int truerailway[201]; //最终最优路线
int railway_=0; //当前经过的城市的个数
int truerailways=-1; //最优路线经过城市的个数
char cityname[201][4]; //代号转换,将名字转换成数字,后面的conversion函数就是转换功能。
int maxkill=-1; //最优路线歼敌数
int mixdistance=500000; //最短进攻距离
int maxtown=-1; //最优路线解放的城镇的数目
int conversion(char name[4],int N); //城镇代号与数字之间的转化
int compare(char name1[4],char name2[4]); //比较城镇是否相同
void seek(int now ,int distance,int kill,int town);
int main()
{
int N,K;
char wgzf;
int amount;
scanf("%d%d",&N,&K);
scanf("%c",&wgzf);
scanf("%s",cityname[0]);
scanf("%s",cityname[1]);
citys[0].arrive_=0; //初始化第一个城镇(即我方大本营)
citys[0].enemy=0; //我方大本营没有敌军
amount=N-1; //题目要求N-1条路线
int cityname_=2; //已经初始化了两个城镇,所以从第三个城镇开始计数
while(amount--) //输入,并初始化所有城镇注意由于先前只输入一个敌方大本营,并没有输入敌人人数。
{
int number;
scanf("%s",cityname[cityname_]);
scanf("%d",&number);
if(compare(cityname[1],cityname[cityname_])) //判断是否为敌方大本营,是的话初始化敌人个数
{
citys
b1b3
[1].enemy=number;
citys[1].arrive_=0;
}
else
{
citys[cityname_].enemy=number;
citys[cityname_].arrive_=0;
cityname_++;
}
}
while(K--) //输入路线以及距离(注意两个城镇都要初始化)
{
char name1[4];
char name2[4];
int distance;
scanf("%s",name1);
scanf("%s",name2);
scanf("%d",&distance);
int id1,id2;
id1=conversion(name1,N);
id2=conversion(name2,N);
citys[id1].arrive[citys[id1].arrive_].cityid=id2;
citys[id1].arrive[citys[id1].arrive_++].distance=distance;
citys[id2].arrive[citys[id2].arrive_].cityid=id1;
citys[id2].arrive[citys[id2].arrive_++].distance=distance;
}
int times; //标记大本营
symbol[0]=1;
seek(0,0,0,0);
int hh;
printf("%s",cityname[0]);
for(hh=0;hh<truerailways;hh++)
printf("->%s",cityname[truerailway[hh]]);
printf("\n");
printf("%d %d %d",rails,mixdistance,maxkill);
}
int compare(char name1[4],char name2[4]) //比较函数
{
char *p1,*p2;
p1=name1;
p2=name2;
while(*p1==*p2 && *p1!='\0')
{
p1++;
p2++;
}
if(*p1=='\0')
return 1;
else
return 0;
}
int conversion(char name[4],int N) //转换函数,转换城镇代号
{
int i;
for(i=0;i<N;i++)
if(compare(cityname[i],name))
return i;
return -1;
}
void seek(int now ,int distance,int kill,int town) //查询函数,枚举回溯每一条路线
{
kill+=citys[now].enemy;
if(now==1) //终止条件,由于先前定义地方大本营位置为1
{
if(distance<=mixdistance) //是最短距离的时候进行考虑否则直接跳过
{
if(distance<mixdistance)
{
rails=0; //若是新的最短距离,更新最优路线数量
mixdistance=distance;
maxtown=town;
maxkill=kill;
truerailways=railway_;
int times;
for(times=0;times<railway_;times++) //记录最优路线
truerailway[times]=railway[times];
}
else
if(town>=maxtown)
{
if(town>maxtown)
{
maxtown=town;
maxkill=kill;
truerailways=railway_;
int times;
for(times=0;times<railway_;times++) //记录最优路线
truerailway[times]=railway[times];
}
else
if(kill>maxkill)
{
maxkill=kill;
truerailways=railway_;
int times;
for(times=0;times<railway_;times++) //记录最优路线
truerailway[times]=railway[times];
}
}
rails++;
}
return ;
}
int i;
for(i=0;i<citys[now].arrive_;i++) //回溯
{
if(symbol[citys[now].arrive[i].cityid]==0) //判断是否已被标记
{
railway[railway_++]=citys[now].arrive[i].cityid; //记录当前路线
symbol[citys[now].arrive[i].cityid]=1;
seek(citys[now].arrive[i].cityid,distance+citys[now].arrive[i].distance,kill,town+1);
symbol[citys[now].arrive[i].cityid]=0; //
railway_--; //返回初始状态
}
}
}
相关文章推荐
- PTA天梯地图
- PTA 一 直捣黄龙
- pat 团体天梯 L3-011. 直捣黄龙
- 2016年团体程序设计天梯赛-决赛 L3-2 直捣黄龙 (最短路)
- PTA 一 天梯地图
- pta 天梯地图 (Dijkstra)
- pta 天梯地图 (Dijkstra)
- PTA 寻找大富翁(25分)
- 第十四,十五周PTA作业
- PTA习题 一元多项式的乘法与加法运算
- 哈尔滨理工大学第七届程序设计竞赛决赛(网络赛-高年级组)B题幸运大奖
- 哈尔滨理工大学第七届程序设计竞赛决赛(网络赛-高年级组)A 所有情况的和(思维题)
- 2017CUIT & FJUT & SWPU三校联合新生赛-决赛 D,E
- 2017CUIT & FJUT & SWPU三校联合新生赛-决赛 D,E
- 哈尔滨理工大学第七届程序设计竞赛决赛(现场赛-高年级组) A-所有情况的和
- PTA习题3.12 另类循环队列
- PTA 6-2 单链表元素定位(12 分)
- PTA计算职工工资
- 哈尔滨理工大学第七届程序设计竞赛决赛(网络赛-高年级组)H - 字典序最小的中序遍历
- 哈尔滨理工大学第七届程序设计竞赛决赛(网络赛-高年级组)B 幸运大奖【DP】