P4524 [COCI2017-2018 Contest4] Ceste

Captain_Paul

2018-11-06 17:45:15

Solution

题意:一个无向图,每条边有两个参数$t$和$c$,定义一条路径的长度为其上$t$之和与$c$之和的乘积,求点$1$到其他点的最短路,不连通输出$-1$ ------------ 用了一下午终于过了~太感人了 最短路当然要用$Dijkstra$了 但是怎么维护$t$之和与$c$之和的乘积呢~ ~~陷入沉思~~ 经过百折不挠的思考和求助 得到正解: 用$Dijkstra$,堆里面按照$t \times c$的大小排序 这里的$t$和$c$就是一条路径上的$t$和$c$之和 再对每个点维护一个$set$,记录到这个点时的$t$和$c$ 以$t$为第一关键字,$c$为第二关键字排序 最短路过程中判断是否可行即可 **感谢$@TimeTraveller$大佬对蒟蒻的帮助!** **我为什么这么菜** ------------ 如果你在$2018.11.10$之前看到了这篇题解 那么~ $NOIP2018$ $rp++$! ``` #include<cstdio> #include<cstring> #include<cctype> #include<queue> #include<set> #include<algorithm> #define reg register using namespace std; typedef long long ll; const int N=2005; struct E { int to,nxt,d1,d2; }edge[N<<1]; struct node { int x; ll t,c; inline friend bool operator < (node a,node b) {return a.t*a.c>b.t*b.c;} }; struct snode { ll t,c; inline friend bool operator < (snode a,snode b) {return a.t==b.t?a.c<b.c:a.t<b.t;} }; int n,m,num,cnt=1,head[N],f[N],vis[N],tcnt; ll ans[N]; priority_queue<node>q; set<snode>S[N]; inline int read() { int x=0,w=1; char c=getchar(); while (!isdigit(c)&&c!='-') c=getchar(); if (c=='-') c=getchar(),w=-1; while (isdigit(c)) { x=(x<<1)+(x<<3)+c-'0'; c=getchar(); } return x*w; } inline void add_edge(int from,int to,int d1,int d2) { edge[++num]=(E){to,head[from],d1,d2}; head[from]=num; } int find(int x){return f[x]==x?x:f[x]=find(f[x]);} inline bool check(int x,snode u) { set<snode>::iterator i; for (i=S[x].lower_bound(u);i!=S[x].end()&&i->c>=u.c;i++) S[x].erase(i); if (i!=S[x].begin()) {--i; if (i->c<u.c) return 0;} S[x].insert(u); return 1; } inline void Dijkstra(int s) { q.push((node){s,0,0}); while (!q.empty()) { node u=q.top(); q.pop(); if (!check(u.x,(snode){u.t,u.c})) continue; if (!vis[u.x]) vis[u.x]=1,ans[u.x]=u.t*u.c,++tcnt; if (tcnt==cnt) return; for (reg int i=head[u.x];i;i=edge[i].nxt) { int v=edge[i].to,t=edge[i].d1,c=edge[i].d2; q.push((node){v,u.t+t,u.c+c}); } } } int main() { n=read(),m=read(); for (reg int i=1;i<=n;i++) f[i]=i,ans[i]=-1; for (reg int i=1;i<=m;i++) { int a=read(),b=read(),c=read(),d=read(); add_edge(a,b,c,d); add_edge(b,a,c,d); if (find(a)!=find(b)) f[f[a]]=f[b]; } for (reg int i=2,rt=find(1);i<=n;i++) if (find(i)==rt) ++cnt; Dijkstra(1); for (reg int i=2;i<=n;i++) printf("%lld\n",ans[i]); return 0; } ```