您的位置:首页 > 其它

2017年计蒜客比赛复赛B D两题

2017-06-11 13:37 351 查看
B题目:https://nanti.jisuanke.com/t/15967  

分析:让你判断最后画在该点上的最后的线段标号,采用直线的上点的更新,(斜率存在和斜率不存在)记录每个点的最后的画上去线段的编号

AC代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <queue>
#include <map>
#include <vector>
#include <cstring>
#include <algorithm>
#include <set>
using namespace std;

const int max_n = 255;
int n,m,q;
int gra[max_n][max_n];
int a,b,c,d;

int main() {
scanf("%d%d",&n,&m);
memset(gra,0,sizeof(gra));
for(int i = 1; i <= n; i++) {
scanf("%d%d%d%d",&a,&b,&c,&d);
if(a == c) {
int y = b,my=d;
if(b > d) {
y = d;
my = b;
}
for(; y <= my; ++y) {
gra[a][y] = i;
}
} else {
double k = ((b-d)*1.0)/(a-c);
int x = a,mx = c;
if(a > c) {
x = c;
mx = a;
}
for(; x <= mx; x++) {
int y = (k*(x-a)+b)*1.0+0.5;
if((b-y)*(c-x) == (d-y)*(a-x)) {
gra[x][y] = i;
}
}
}
}
scanf("%d",&q);
while(q--) {
scanf("%d%d",&a,&b);
printf("%d\n",gra[a][b]);
}
return 0;
}


注意:此题会卡精度啊,必须加上0.5进行四舍五入啊,gg!

D题目:https://nanti.jisuanke.com/t/15969 

百度地图上有 nn 个城市,城市编号依次为 11 到 nn。地图中有若干个城市群,编号依次为 11 到 mm。每个城市群包含一个或多个城市;每个城市可能属于多个城市群,也可能不属于任何城市群。
地图中有两类道路。第一类道路是 城市之间的快速路,两个城市 u,vu,v 之间增加一条距离为 cc 的边;第二类道路是 城市群之间的高速路,连接两个城市群 a,ba,b,通过这条高速路,城市群 aa 里的每个城市与城市群 bb 里的每个城市之间两两增加一条距离为 cc 的边。图中所有边均为无向边。

你需要计算从城市 ss 到城市 tt 的最短路。

输入格式

第一行输入 n(1
\le n \le 20000),n(1≤n≤20000), m(0
\le m \le 20000)m(0≤m≤20000),分别表示城市总数和城市群总数。

接下来一共输入 mm 行。

第 ii 行首先输入一个 k_i(1
\le k_i \le n)k​i​​(1≤k​i​​≤n),表示第 ii个城市群中的城市数为 k_ik​i​​。接下来输入 k_ik​i​​ 个数,表示第 ii 个城市群中每个城市的编号(保证一个城市群内的城市编号不重复且合法,\sum_{i=1}^{m}k_i
\le 20000∑​i=1​m​​k​i​​≤20000)。

下一行输入一个整数 m_1(0
\le m_1 \le 20000)m​1​​(0≤m​1​​≤20000),表示有 m_1m​1​​ 条第一类道路,即 城市之间的快速路。

接下来 m_1m​1​​ 行,每行输入三个整数 u_i,v_i(1
\le u_i, v_i \le n),c_i(1 \le c_i \le 10^6)u​i​​,v​i​​(1≤u​i​​,v​i​​≤n),c​i​​(1≤c​i​​≤10​6​​),分别表示快速路连接的两个城市编号和边的距离。

下一行输入一个整数 m_2(0
\le m_2 \le 20000)m​2​​(0≤m​2​​≤20000),表示有 m_2m​2​​ 条第二类道路,即 城市群之间的高速路。

接下来 m_2m​2​​ 行,每行输入三个整数 a_i,b_i(1
\le a_i, b_i \le m),l_i(1 \le l_i \le 10^6)a​i​​,b​i​​(1≤a​i​​,b​i​​≤m),l​i​​(1≤l​i​​≤10​6​​),分别表示快速路连接的两个城市群编号和边的距离。

最后一行输入 s,
t(1 \le s, t \le n)s,t(1≤s,t≤n),表示起点和终点城市编号。

输出格式

输出一个整数,表示城市 ss 到城市 tt 到最短路。如果不存在路径,则输出
-1


样例说明

1
-> 2 - > 5
或者
1 -> 4 -> 5
是最短的路径,总长度为 1212。

样例输入

5 4
2 5 1
2 2 4
1 3
2 3 4
2
1 2 9
1 5 18
2
1 2 6
1 3 10
1 5


样例输出

12


分析:基本思路:用优先队列优化一下的Dijkstra()算法,问题在于,我们如何见图,城市之间的图容易见,主要是群之间如何建立图,城市和群之间建图,首先我们将群号分成两部分n+1~n+m表示第一批的序号,n+m+1~n+m+m表示第二批的序号,那么建图就可以转成,城市到第一批的建立,第一批到第二批群之间的建立,其实说白了就是转折:城市-群-城市,这样解决了题目中每个群之间所有的所有城市建录得问题

AC 代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <queue>
#include <map>
#include <vector>
#include <cstring>
#include <algorithm>
#include <set>
using namespace std;

typedef long long LL;
const int max_m = 20010;
const LL INF = 0x3f3f3f3f3f3f3f3f;
int n,m;
int a,b,m1,m2;
LL c;
vector<pair<int,LL> >gra[3*max_m];
LL d[3*max_m];

void dijkstra(int s) {
priority_queue<pair<LL,int> >Q;//这样定义主要是为了以pair的第一个元素排序
for(int i = 1; i <= n+2*m; i++) d[i] = INF;
d[s] = 0;
Q.push(pair<int,LL>(0,s));
while(!Q.empty()) {
int u = Q.top().second;
Q.pop();
for(int i = 0; i < gra[u].size(); i++) {
int to = (gra[u][i].first);
int dist = gra[u][i].second;
if(d[to] > d[u] + dist) {
d[to] = d[u] + dist;
Q.push(pair<int,int>(-d[to],to));//为什么这里我们要-d[to]呢?原因在于优先队列默认从大到小排序,那么-d[to]就得出最小的一定在优先队列的首位
}
}
}
}
/**
定义:1~n表示城市编号,n+1~n+m表示群的编号,n+m+1 ~ n+2*m表示群的编号
即有n+i对应的群编号 = n+m+i对应的群编号;
*/
int main() {
scanf("%d%d",&n,&m);
int k;
for(int i = 1; i <= m; i++) {
scanf("%d",&k);
for(int j = 0; j < k; j++) {
scanf("%d",&a);
gra[a].push_back(pair<int,int>(n+i,0));//建立城市到群号之间的距离为0
gra[n+m+i].push_back(pair<int,int>(a,0));//建立群号到城市之间的图
}
}
scanf("%d",&m1);
while(m1--) {
scanf("%d%d%lld",&a,&b,&c);
gra[a].push_back(pair<int,int>(b,c));//建立城市之间的图
gra[b].push_back(pair<int,int>(a,c));
}
scanf("%d",&m2);
for(int i = 0; i < m2; ++i) {
scanf("%d%d%lld",&a,&b,&c);
gra[a+n].push_back(pair<int,int>(b+m+n,c));//建立群与群之间的图
gra[b+n].push_back(pair<int,int>(a+m+n,c));
}
scanf("%d%d",&a,&b);
if(a == b) {
printf("0\n");
return 0;
}
dijkstra(a);
if(d[b] == INF) {
printf("-1\n");
} else {
printf("%lld\n",d[b]);
}
return 0;
}

当然,优先队列用pair可能不好理解,那么我们可以使用,自定义结构体:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <queue>
#include <map>
#include <vector>
#include <cstring>
#include <algorithm>
#include <set>
using namespace std;

typedef long long LL;
const int max_m = 20010;
const LL INF = 0x3f3f3f3f3f3f3f3f;
int n,m;
int a,b,m1,m2;
LL c;
vector<pair<int,LL> >gra[3*max_m];
LL d[3*max_m];
struct HeapNode {
int d,u;
bool operator < (const HeapNode& rhs) const {
return d > rhs.d;
}
} p,pp;
void dijkstra(int s) {
priority_queue<HeapNode>Q;
for(int i = 1; i <= n+2*m; i++) d[i] = INF;
d[s] = 0;
p.u = s;
p.d = 0;
Q.push(p);
while(!Q.empty()) {
p = Q.top();
Q.pop();
int u = p.u;
for(int i = 0; i < gra[u].size(); i++) {
int to = (gra[u][i].first);
int dist = gra[u][i].second;
if(d[to] > d[u] + dist) {
d[to] = d[u] + dist;
pp.u = to;
pp.d = d[to];
Q.push(pp);
}
}
}
}

int main() {
scanf("%d%d",&n,&m);
int k;
for(int i = 1; i <= m; i++) {
scanf("%d",&k);
for(int j = 0; j < k; j++) {
scanf("%d",&a);
gra[a].push_back(pair<int,int>(n+i,0));//建立城市到群号之间的距离为0
gra[n+m+i].push_back(pair<int,int>(a,0));//建立群号到城市之间的图
}
}
scanf("%d",&m1);
while(m1--) {
scanf("%d%d%lld",&a,&b,&c);
gra[a].push_back(pair<int,int>(b,c));//建立城市之间的图
gra[b].push_back(pair<int,int>(a,c));
}
scanf("%d",&m2);
for(int i = 0; i < m2; ++i) {
scanf("%d%d%lld",&a,&b,&c);
gra[a+n].push_back(pair<int,int>(b+m+n,c));//建立群与群之间的图
gra[b+n].push_back(pair<int,int>(a+m+n,c));
}
scanf("%d%d",&a,&b);
if(a == b) {
printf("0\n");
return 0;
}
dijkstra(a);
if(d[b] == INF) {
printf("-1\n");
} else {
printf("%lld\n",d[b]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  最短路 暴力模拟