洛谷 P2573 [SCOI2012]滑雪
Posted 弥生三月
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了洛谷 P2573 [SCOI2012]滑雪相关的知识,希望对你有一定的参考价值。
题目描述
a180285非常喜欢滑雪。他来到一座雪山,这里分布着M条供滑行的轨道和N个轨道之间的交点(同时也是景点),而且每个景点都有一编号i(1<=i<=N)和一高度Hi。a180285能从景点i 滑到景点j 当且仅当存在一条i 和j 之间的边,且i 的高度不小于j。 与其他滑雪爱好者不同,a180285喜欢用最短的滑行路径去访问尽量多的景点。如果仅仅访问一条路径上的景点,他会觉得数量太少。于是a180285拿出了他随身携带的时间胶囊。这是一种很神奇的药物,吃下之后可以立即回到上个经过的景点(不用移动也不被认为是a180285 滑行的距离)。请注意,这种神奇的药物是可以连续食用的,即能够回到较长时间之前到过的景点(比如上上个经过的景点和上上上个经过的景点)。 现在,a180285站在1号景点望着山下的目标,心潮澎湃。他十分想知道在不考虑时间
胶囊消耗的情况下,以最短滑行距离滑到尽量多的景点的方案(即满足经过景点数最大的前提下使得滑行总距离最小)。你能帮他求出最短距离和景点数吗?
输入输出格式
输入格式:
输入的第一行是两个整数N,M。
接下来1行有N个整数Hi,分别表示每个景点的高度。
接下来M行,表示各个景点之间轨道分布的情况。每行3个整数,Ui,Vi,Ki。表示
编号为Ui的景点和编号为Vi的景点之间有一条长度为Ki的轨道。
输出格式:
输出一行,表示a180285最多能到达多少个景点,以及此时最短的滑行距离总和。
输入输出样例
3 3 3 2 1 1 2 1 2 3 1 1 3 10
3 2
说明
【数据范围】
对于30%的数据,保证 1<=N<=2000
对于100%的数据,保证 1<=N<=100000
对于所有的数据,保证 1<=M<=1000000,1<=Hi<=1000000000,1<=Ki<=1000000000。
这题目的题意真是看不懂
大概意思是给出一张有向图,边的方向是从高到低,让你求一个最小树形图
朱刘算法怒艹1e13也不是不可以啊
这道题的思路确实很妙,没看题解想不到
首先观察发现能到达的点就是一遍BFS,这些点肯定都要到达
然后走过的路径是一个以1为根的最小树形图
直接朱刘算法肯定不行,需要考虑别的办法
这张图的的性质是边只从高连向低,同高度之间是无向边
如果把点按照高度分层,那么有向边只从高的一层连向低的一层,层内只有无向边
这有什么用呢?
我们知道,对于无向图的树形图(即生成树),有很优秀的办法来解决,为什么kruskal和prim不能做有向图的树形图呢?稍微尝试几个例子以后会发现,如果用无向图的方法来做,会有两个问题
1、答案不是最优,这是由于prim的加入顺序问题导致的
2、做出来的根本不是树形图,kruskal没法处理这种情况
但是对于DAG这种特殊的图而言,无向图的方法加上一些魔改就可以做了,对于kruskal而言,把边按照终点的拓扑序为第一关键字,边长为第二关键字排序,然后往里加就行了
让我们回到这道题的图,我们发现这张图很像是一层层的DAG加上层内的无向图,是不是胡搞一下就好了啊?
发现是的,一样这么做就行,第一关键字h降序,第二关键字变长升序,原因是这样既不会产生第一个问题(按顺序一层层加入,答案不会变劣),也不会产生第二个问题(层间不会有问题,层内是无向边,可以随意分配)
然后跑kruskal即可
1 #include <iostream> 2 #include <cstdlib> 3 #include <cstdio> 4 #include <algorithm> 5 #include <string> 6 #include <cstring> 7 #include <cmath> 8 #include <map> 9 #include <stack> 10 #include <set> 11 #include <vector> 12 #include <queue> 13 #include <time.h> 14 #include <functional> 15 #define eps 1e-7 16 #define INF 0x3f3f3f3f 17 #define MOD 1000000007 18 #define rep0(j,n) for(int j=0;j<n;++j) 19 #define rep1(j,n) for(int j=1;j<=n;++j) 20 #define pb push_back 21 #define set0(n) memset(n,0,sizeof(n)) 22 #define ll long long 23 #define ull unsigned long long 24 #define iter(i,v) for(edge *i=head[v];i;i=i->nxt) 25 #define max(a,b) (a>b?a:b) 26 #define min(a,b) (a<b?a:b) 27 #define print_runtime printf("Running time:%.3lfs\n",double(clock())/1000.0) 28 #define TO(j) printf(#j": %d\n",j); 29 //#define OJ 30 using namespace std; 31 const int MAXINT = 100010; 32 const int MAXNODE = 100010; 33 const int MAXEDGE = 4 * 1000010; 34 char BUF, *buf; 35 int read() { 36 char c = getchar(); int f = 1, x = 0; 37 while (!isdigit(c)) {if (c == ‘-‘) f = -1; c = getchar();} 38 while (isdigit(c)) {x = x * 10 + c - ‘0‘; c = getchar();} 39 return f * x; 40 } 41 char get_ch() { 42 char c = getchar(); 43 while (!isalpha(c)) c = getchar(); 44 return c; 45 } 46 //------------------- Head Files ----------------------// 47 int cnt, n, m; 48 int vis[MAXNODE],ans,h[MAXNODE],qu[MAXNODE],fa[MAXNODE]; 49 struct edge { 50 int u, v, l; 51 edge *nxt; 52 edge(int _u, int _v, int _l, edge * _nxt): u(_u), v(_v), l(_l), nxt(_nxt) {} 53 edge() {} 54 } mp[MAXEDGE], *head[MAXNODE]; 55 bool operator < (const edge &a,const edge &b){ 56 return h[a.v]==h[b.v]?a.l<b.l:h[a.v]>h[b.v]; 57 } 58 void get_input(); 59 void work(); 60 void addedge(int u, int v,int l) { 61 mp[cnt] = edge(u, v, l,head[u]); 62 head[u] = &mp[cnt++]; 63 } 64 /*void spfa(int ss, int tt) { 65 memset(dis, 0x3f, sizeof(dis)); 66 dis[ss] = 0; 67 int *h, *t; 68 h = t = q; 69 *t++ = ss; 70 while (h != t) { 71 int p = *h++; inq[p] = 0; 72 iter(i, p) { 73 if (dis[i->v] > dis[p] + i->l) { 74 dis[i->v] = dis[p] + i->l; 75 if (!inq[i->v]) { 76 *t++ = i->v; 77 inq[i->v] = 1; 78 } 79 } 80 } 81 } 82 }*/ 83 /*void dijkstra(int ss,int tt){ 84 memset(dis,0x3f,sizeof(dis)); 85 dis[ss]=0; 86 q.push(make_pair(0,ss)); 87 int T=n-1; 88 while(T--){ 89 while(!q.empty()&&vis[q.top().second]) q.pop(); 90 if(q.empty()) break; 91 int p = q.top().second;q.pop(); 92 iter(i,p){ 93 if(dis[i->v]>dis[p]+i->l){ 94 dis[i->v]=dis[p]+i->l; 95 q.push(make_pair(dis[i->v],i->v)); 96 } 97 } 98 } 99 }*/ 100 void bfs(int p){ 101 int *h,*t; 102 h=t=qu; 103 vis[1]=1;ans=1; 104 *t++=1; 105 while(h!=t){ 106 int p=*h++; 107 iter(i,p){ 108 if(!vis[i->v]) {vis[i->v]=1;ans++;*t++=i->v;} 109 } 110 } 111 } 112 int findfa(int p) {return p==fa[p]?p:fa[p]=findfa(fa[p]);} 113 int main() { 114 get_input(); 115 work(); 116 return 0; 117 } 118 void work() { 119 //dijkstra(1,n); 120 bfs(1); 121 rep1(i,n) fa[i]=i; 122 sort(mp,mp+cnt); 123 ull sum=0; 124 rep0(i,cnt){ 125 int u=mp[i].u,v=mp[i].v; 126 if(!vis[u]||!vis[v]) continue; 127 u=findfa(u);v=findfa(v); 128 if(u!=v) {fa[u]=v; sum+=mp[i].l;} 129 } 130 printf("%d %llu\n",ans,sum); 131 } 132 void get_input() { 133 n = read(); m = read(); 134 rep1(i, n) h[i] = read(); 135 rep0(i, m) { 136 int u = read(), v = read(), l = read(); 137 if (h[u] > h[v]) addedge(u, v, l); 138 if (h[u] == h[v]) {addedge(u, v, l); addedge(v, u, l);} 139 if (h[u] < h[v]) addedge(v, u, l); 140 } 141 142 }
以上是关于洛谷 P2573 [SCOI2012]滑雪的主要内容,如果未能解决你的问题,请参考以下文章
P2573 [SCOI2012]滑雪(kruskal&bfs)