L2-001 紧急救援 (25 分)
分析:
一看就是迪杰斯特拉 求最短路径,但是还是有点晕,今晚就去看看,之前做作业的时候就是抄的网上的。除了求最短路径外,还要记录路径的条数,救援队的数量,当然 路径距离一样的情况下 肯定是优先走救援队最多的。每次找到最短路的时候 记录前驱,递归函数打印路径。
代码:
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
int n,m,c1,c2;//N城市个数,M快速路条数,c1出发地编号,c2目的地编号
int weight[510],dis[510],e[510][510],num[510],w[510],pre[510];
int visit[510];
const int inf =9999999;
void printPath(int v)//利用递归 打印路径(路径本身顺序是倒着的)
{
if(v==c1)
{
printf("%d",v);//递归退出条件
return ;
}
printPath(pre[v]);
printf(" %d",v);
}
int main()
{
scanf("%d%d%d%d",&n,&m,&c1,&c2);
for(int i=0;i<n;i++)
scanf("%d",&weight[i]);//每个城市的救援队数量
fill(e[0],e[0]+510*510,inf);
fill(dis,dis+510,inf);//初始化每个城市的最短距离 与每个城市之间的快速路长度
int a,b,c;
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&a,&b,&c);
e[a][b]=c;
e[b][a]=c;//根据输入完成城市地图的构造
}
dis[c1]=0;//从起点到起点的距离为0
w[c1]=weight[c1];//到起点 能叫的救援队最多为起点本地的救援队数量
num[c1]=1;//道路有1条
for(int i=0;i<n;i++)//用迪杰斯特拉找到 到每个点最短距离
{
int u=-1,minn=inf;
for(int j=0;j<n;j++)//找到当前可以到达的距离最短的点
{
if(visit[j]==false&&dis[j]<minn)
{
u=j;
minn=dis[j];//目前的最短距离
}
}
if(u==-1) break;//说明所有的点都已经找到
visit[u]=true;
for(int v=0;v<n;v++)
{
if(visit[v]==false&&e[u][v]!=inf)//从剩下没到达的点找
{
if(dis[u]+e[u][v]<dis[v])//如果到v点 通过u 更短 刷新v的dis
{
dis[v]=dis[u]+e[u][v];
num[v]=num[u];//路的条数是一样的
w[v]=w[u]+weight[v];//救援队数量增多
pre[v]=u;//v的前驱是u
}
else if(dis[u]+e[u][v]==dis[v])//如果距离一样 说明多了一条路
{
num[v]=num[v]+num[u];
if(w[u]+weight[v]>w[v])//距离一样的情况下 肯定优先走救援队伍多的路
{
w[v]=w[u]+weight[v];
pre[v]=u;
}
}
}
}
}
printf("%d %d\n",num[c2],w[c2]);
printPath(c2);
return 0;
}
L2-002 链表去重 (25 分)
代码:
晕死了 看了半天也不知道为啥测试点4和5过不了
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
typedef struct
{
int key;
int next;
}Node;
void bu(int i)
{
if(i==-1)
return;
if(i>=0&&i<10)//只有个位
cout<<"0000";
else if(i<100)//只要十位
cout<<"000" ;
else if(i<1000)//只有百位
cout<<"00";
else if(i<10000)
cout<<"0";
}
int main()
{
Node res[100000];
int first,num;
scanf("%d %d",&first,&num);//输入第一个结点地址 与结点总数
for(int i=0;i<num;i++)
{
int a,b,c;
scanf("%d %d %d",&a,&b,&c);//输入结点
res[a].key=b;
res[a].next=c;
}
int p=first;//第一个开始
bool isdel=false;//标记是否已经有删除链表
bool d[10001];//是否重复
fill(d,d+10001,false);
d[res[p].key]=true;//初始化第一个
int dfirst=-1;
int q=-1;
while(res[p].next!=-1)
{
if(d[abs(res[res[p].next].key)]==false)//如果绝对值没有重复
{
d[abs(res[res[p].next].key)]=true;
p=res[p].next;
}
else//如果重复
{
if(isdel==false)//如果在此之前还没有重复的
{
dfirst=res[p].next;//让其变成删除链表的第一个
q=dfirst;
res[p].next=res[res[p].next].next;//等于下下个
isdel=true;
}
else//删除重复结点
{
res[q].next=res[p].next;//接在删除链表后面
res[p].next=res[res[p].next].next;//让其下一个变成其下一个的下一个
q=res[q].next;
}
}
}//该循环还没有处理最后一个结点
res[q].next=-1;
p=first;
q=dfirst;
while(p!=-1)
{
bu(p);
cout<<p<<' '<<res[p].key<<' ';
bu(res[p].next);
cout<<res[p].next<<endl;
p=res[p].next;
}
while(q!=-1)
{
bu(q);
cout<<q<<' '<<res[q].key<<' ';
bu(res[q].next);
cout<<res[q].next<<endl;
q=res[q].next;
}
}
分析:
自己的死活过不了,只好去看大佬的了。大佬的想法有点神奇,大概是把整个链表放在同一个数组内保存,分成两部分,一部分是没重复的,一部分是重复的。通过给编号(给编号的时候是按照链表的顺序给的)将两个部分分隔开 排序后 ,不是用Next输出下一个,而是数组的下一个(就是正常情况的next 先输入的输出)
代码:
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int maxn=100000;
struct NODE{
int address;
int key;
int next;
int num;
}node[maxn];
bool exist[maxn];
int cmp1(NODE a,NODE b)
{
return a.num<b.num;//根据编号排序
}
int main()
{
int begin,n,cnt1=0,cnt2=0,a;//cnt1没有删除的结点个数
scanf("%d%d",&begin,&n);
for(int i=0;i<maxn;i++)
{
node[i].num=2*maxn;//初始化编号
}
for(int i=0;i<n;i++)
{
scanf("%d",&a);//地址
scanf("%d%d",&node[a].key,&node[a].next);//值与下一个的地址
node [a].address =a;
}
for(int i=begin;i!=-1;i=node[i].next)
{
if(exist[abs(node[i].key)]==false)//如果没有重复
{
exist[abs(node[i].key)]=true;
node[i].num=cnt1;
cnt1++;
}
else
{
node[i].num=maxn+cnt2;
cnt2++;
}
}
sort(node,node+maxn,cmp1);//按照编号排序
int cnt=cnt1+cnt2;//总共需要输出的数量
for(int i=0;i<cnt;i++)
{
if(i!=cnt1-1&&i!=cnt-1)
{
printf("%05d %d %05d\n",node[i].address,node[i].key,node[i+1].address);
}
else
{
printf("%05d %d -1\n",node[i].address,node[i].key);
}
}
return 0;
}