【牛客 - 370B】Rinne Loves Graph(分层图最短路 或 最短路dp)
題干:
?
Island 發(fā)生了一場暴亂!現(xiàn)在 Rinne 要和 Setsuna 立馬到地上世界去。
眾所周知:Island 是有一些奇怪的城鎮(zhèn)和道路構(gòu)成的(題目需要,游戲黨勿噴),有些城鎮(zhèn)之間用雙向道路連接起來了,且每條道路有它自己的距離。但是有一些城鎮(zhèn)已經(jīng)被派兵戒嚴(yán),雖然主角可以逆天改命強(qiáng)闖,但是為了體驗該游戲的平衡性,他們只能穿過不超過 K 次被戒嚴(yán)的城鎮(zhèn)。
定義“穿過”:從一個戒嚴(yán)的點(diǎn)出發(fā)到達(dá)任意一個點(diǎn),都會使得次數(shù)加1
現(xiàn)在他們想從 1 號城鎮(zhèn)最快的走到 n 號城鎮(zhèn)(即出口),現(xiàn)在他們想讓你告訴他們最短需要走多少路。
輸入描述:
第一行三個整數(shù) n,m,k,分別表示城鎮(zhèn)數(shù)量,邊數(shù)量和最多能闖過被戒嚴(yán)的城市的次數(shù)。 接下來 n 行,每行一個整數(shù) 1 或 0,如果為 1 則表示該城市已被戒嚴(yán),0 則表示相反。 接下來 m 行,每行三個數(shù) u,v,w,表示在 u 城鎮(zhèn)和 v 城鎮(zhèn)之間有一條長度為 w 的雙向道路。輸出描述:
輸出一行一個數(shù)字,表示從 1 到 n 的最短路徑,如果到達(dá)不了的話,請輸出 -1。示例1
輸入
復(fù)制
4 5 1 1 0 1 0 1 2 10 2 3 10 3 1 15 1 4 60 3 4 30輸出
復(fù)制
60備注:
2≤n≤800,1≤m≤4000,1≤k≤10,1≤w≤1062≤n≤800,1≤m≤4000,1≤k≤10,1≤w≤106保證沒有多條道路連接同一對城市,也沒有一條道路連向自己。
解題報告:
這題可以dp,dp[i][j]表示從1到 i ,穿過j次戒煙戒嚴(yán)城鎮(zhèn),的最短路。(最近這種題見了三道了。)。也可以k - 分層圖。(下面有好幾個分層圖代碼,建圖方式和做法有所不同)。也可以直接類似bfs的Dijkstra。。
AC代碼1:(分層圖)
#include<cstdio> #include<iostream> #include<algorithm> #include<queue> #include<map> #include<vector> #include<set> #include<string> #include<cmath> #include<cstring> #define ll long long #define pb push_back #define pm make_pair using namespace std; const int MAX = 800 + 5; const int INF = 0x3f3f3f3f; int tot; int n,m,k; int a[MAX]; int dis[MAX*15],head[MAX*15]; bool vis[MAX*15]; struct Edge {int to,ne;int w; } e[8005*15]; struct Point {int id;int c;Point() {}Point(int id,int c):id(id),c(c) {}bool operator <(const Point & b) const {return c>b.c;} }; void add(int u,int v,int w) {e[++tot].to = v;e[tot].w = w;e[tot].ne = head[u];head[u] = tot; } void Dijkstra() {memset(dis,INF,sizeof dis);dis[1] = 0;priority_queue<Point> pq;pq.push(Point(1,0));while(pq.size()) {Point cur = pq.top(); pq.pop(); // if(vis[cur.id]) continue;這兩句加不加都可以AC // vis[cur.id] = 1;for(int i = head[cur.id]; i!=-1; i = e[i].ne) {if(dis[e[i].to]>e[i].w+cur.c) {dis[e[i].to]=e[i].w+cur.c;pq.push(Point(e[i].to,dis[e[i].to]));}}} }int main() {memset(head,-1,sizeof head);scanf("%d%d%d",&n,&m,&k);for (int i=1; i<=n; i++) scanf("%d",&a[i]);for (int i=1; i<=m; i++) {int x,y,w;scanf("%d%d%d",&x,&y,&w);if(!a[x]) {for(int j = 0; j<=k; j++) add(x+n*j,y+n*j,w);}if(!a[y]) {for(int j = 0; j<=k; j++) add(y+n*j,x+n*j,w);}if(a[x]) {for(int j = 0; j<k; j++) add(x+n*j,y+n*(j+1),w);}if(a[y]) {for(int j = 0; j<k; j++) add(y+n*j,x+n*(j+1),w);} }if (k<0) {printf("-1\n");return 0;}Dijkstra();int ans = INF;for (int i = 1; i<=k+1; i++) ans=min(ans,dis[i*n]);if (ans == INF) ans = -1;printf("%d\n",ans);return 0 ; }一個大佬的分層圖:
#include<cstdio> #include<algorithm> #include<cmath> #include<cstring> using namespace std; const int N=2e5+10; int a[N],he[N*10],t[N*20],ne[N*20],d[N*400],vis[N*10],tot=0; long long dis[N],cc[N*20]; void link(int x,int y,long long z) {tot++;ne[tot]=he[x];he[x]=tot;t[tot]=y;cc[tot]=z; } int main() {int n,m,k;scanf("%d%d%d",&n,&m,&k);for (int i=1;i<=n;i++) scanf("%d",&a[i]);if (a[1]) k--;if (a[n]) k++;for (int i=1;i<=m;i++){int x,y;long long z;scanf("%d%d%lld",&x,&y,&z);for (int j=0;j<=k;j++){if (!a[x]) link(y+n*j,x+n*j,z);if (!a[y]) link(x+n*j,y+n*j,z);}for (int j=0;j<k;j++){if (a[x]) link(y+n*j,x+n*(j+1),z);if (a[y]) link(x+n*j,y+n*(j+1),z);}}if (k<0){printf("-1\n");return 0;}int i=0,kk=1;d[1]=1;dis[1]=0;for (int i=2;i<=n*(k+1);i++) dis[i]=(long long)m*40000000;i=0;while (i<kk){i++;int u=d[i];for (int j=he[u];j;j=ne[j]){if (dis[u]+cc[j]<dis[t[j]]){dis[t[j]]=dis[u]+cc[j];kk++;d[kk]=t[j];}}}long long ans=(long long)m*40000000;for (int i=1;i<=k+1;i++) ans=min(ans,dis[i*n]);if (ans==(long long)m*40000000) ans=-1;printf("%lld\n",ans);分層圖標(biāo)程:
#include <algorithm> #include <iostream> #include <cstring> #include <climits> #include <cstdlib> #include <cstdio> #include <queue> #include <stack> #include <map> #include <set> #define LL long longconst int MAXN = 800 + 5; const int MAXM = 4000 + 5; const int MAXK = 10 + 5;int N,M,K; using std::queue;struct Node{struct Edge *firstEdge;LL dist;bool inQueue,die; }node[MAXN * MAXN + 2];struct Edge{Node *s,*t;LL w;Edge *next; }pool[MAXM * MAXK * 2],*frog = pool;Edge *New(Node *s,Node *t,LL w){Edge *ret = ++frog;ret->s = s;ret->t = t;ret->w = w;ret->next = s->firstEdge;return ret; }inline void add(int u,int v,LL w){node[u].firstEdge = New(&node[u],&node[v],w);//node[v].firstEdge = New(&node[v],&node[u],w); }LL SPFA(int s,int t,int n){for(int i = 1;i <= n;i++){node[i].dist = LLONG_MAX;node[i].inQueue = false;}queue<Node *> q;q.push(&node[s]);node[s].inQueue = true;node[s].dist = 0;while(!q.empty()){Node *v = q.front();q.pop();v->inQueue = false;for(Edge *e = v->firstEdge;e;e = e->next){if(e->t->dist > v->dist + e->w){e->t->dist = v->dist + e->w;if(!e->t->inQueue){e->t->inQueue = true;q.push(e->t);}}}}return node[t].dist; }int main(){scanf("%d%d%d",&N,&M,&K);for(int x,i = 1;i <= N;i++)scanf("%d",&node[i].die);int s = 0,t = N + N * K + 1;for(int u,v,i = 1;i <= M;i++){LL w;scanf("%d%d%lld",&u,&v,&w);if(!node[u].die)for(int i = 0;i <= K;i++)add(u + N * i,v + N * i,w);if(!node[v].die)for(int i = 0;i <= K;i++)add(v + N * i,u + N * i,w);if(node[u].die)for(int i = 0;i < K;i++)add(u + N * i,v + N * (i + 1),w);if(node[v].die)for(int i = 0;i < K;i++)add(v + N * i,u + N * (i + 1),w);}add(s,1,0);for(int i = 0;i <= K;i++)add(N + (N * i),t,0);LL ans = SPFA(s,t,N*(1 + K) + 2);printf("%lld\n",(ans == LLONG_MAX) ? -1 : ans);//getchar();getchar();return 0; }AC代碼3:(最短路dp)
#include<cstdio> #include<iostream> #include<algorithm> #include<queue> #include<map> #include<vector> #include<set> #include<string> #include<cmath> #include<cstring> #define ll long long #define pb push_back #define pm make_pair using namespace std; const int MAX = 800 + 5; const int INF = 0x3f3f3f3f; int tot; int n,m,k; int a[MAX]; int dis[MAX][15],head[MAX];//dis[i][j]表示從1到 i ,穿過j次戒煙戒嚴(yán)城鎮(zhèn),的最短路。 struct Edge {int to,ne;int w; } e[4005*2]; struct Point {int id;int c,jy;Point() {}Point(int id,int c,int jy):id(id),c(c),jy(jy) {}bool operator <(const Point & b) const {return c>b.c;} }; void add(int u,int v,int w) {e[++tot].to = v;e[tot].w = w;e[tot].ne = head[u];head[u] = tot; } void Dijkstra() {memset(dis,INF,sizeof dis);dis[1][0] = 0;priority_queue<Point> pq;pq.push(Point(1,0,0));while(pq.size()) {Point cur = pq.top();pq.pop();for(int i = head[cur.id]; i!=-1; i = e[i].ne) {int nowjy = a[cur.id] + cur.jy;if( nowjy > k) continue;if(dis[e[i].to][nowjy]>e[i].w+cur.c) {dis[e[i].to][nowjy]=e[i].w+cur.c;pq.push(Point(e[i].to,dis[e[i].to][nowjy],nowjy));}}}} int main() {cin>>n>>m>>k;for(int i = 1; i<=n; i++) scanf("%d",a+i);memset(head,-1,sizeof head);for(int x,y,w,i = 1; i<=m; i++) {scanf("%d%d%d",&x,&y,&w);add(x,y,w);add(y,x,w);}Dijkstra();int ans = INF;for(int i=0; i<=k; i++) {ans=min(ans,dis[n][i]);}if(ans==INF) puts("-1");else printf("%d\n",ans);return 0 ; }當(dāng)然你如果認(rèn)準(zhǔn)了那道“小明的貪心題”,加上這個判斷也無妨(為了避免同一元素多次入隊):
#include<cstdio> #include<iostream> #include<algorithm> #include<queue> #include<map> #include<vector> #include<set> #include<string> #include<cmath> #include<cstring> #define ll long long #define pb push_back #define pm make_pair using namespace std; const int MAX = 800 + 5; const int INF = 0x3f3f3f3f; int tot; int n,m,k; int a[MAX]; int dis[MAX][15],head[MAX]; struct Edge {int to,ne;int w; } e[8005]; struct Point {int id;int c,jy;Point() {}Point(int id,int c,int jy):id(id),c(c),jy(jy) {}bool operator <(const Point & b) const {return c>b.c;} }; void add(int u,int v,int w) {e[++tot].to = v;e[tot].w = w;e[tot].ne = head[u];head[u] = tot; } void Dijkstra() {memset(dis,INF,sizeof dis);dis[1][0] = 0;priority_queue<Point> pq;pq.push(Point(1,0,0));while(pq.size()) {Point cur = pq.top();pq.pop();if(cur.c > dis[cur.id][cur.jy]) continue;for(int i = head[cur.id]; i!=-1; i = e[i].ne) {int nowjy = a[cur.id] + cur.jy;if( nowjy > k) continue;if(dis[e[i].to][nowjy]>e[i].w+cur.c) {dis[e[i].to][nowjy]=e[i].w+cur.c;pq.push(Point(e[i].to,dis[e[i].to][nowjy],nowjy));}}}} int main() {cin>>n>>m>>k;for(int i = 1; i<=n; i++) scanf("%d",a+i);memset(head,-1,sizeof head);for(int x,y,w,i = 1; i<=m; i++) {scanf("%d%d%d",&x,&y,&w);add(x,y,w);add(y,x,w);}Dijkstra();int ans = INF;for(int i=0; i<=k; i++) {ans=min(ans,dis[n][i]);}if(ans==INF) puts("-1");else printf("%d\n",ans);return 0 ; }還可以這么寫最短路這題(看起來不像是Dijkstra反倒像是bfs,但又不是bfs):
#include<bits/stdc++.h> using namespace std; struct edge {int to, next, w; } e[8100]; struct node {int u, k, d;node() {}node(int u, int k, int d) : u(u), k(k), d(d) {}bool operator < (const node &a) const {return d > a.d;} }; int head[888], num; int jy[888]; int n, m, k; void add(int u, int v, int w) {e[num].to = v;e[num].next = head[u];e[num].w = w;head[u] = num++; } int d[888]; void Dijkstra() {//bfsmemset(d, -1, sizeof d);d[1] = 0;priority_queue<node> q;q.push(node(1, 0, 0));while(!q.empty()) {node cur = q.top();q.pop();if(cur.u == n) {printf("%d\n", d[n]);return;}for(int i=head[cur.u]; i!=-1; i=e[i].next) {int v = e[i].to;if(jy[cur.u] && cur.k == k) continue;if(d[v]==-1|| d[v] > cur.d+e[i].w) {d[v] = cur.d+e[i].w;q.push(node(v,cur.k+jy[cur.u],d[v]));}}}puts("-1");return; } int main() {memset(head, -1, sizeof head);num = 0;scanf("%d%d%d",&n,&m,&k);for(int i=1; i<=n; i++) {scanf("%d", &jy[i]);}for(int i=0; i<m; i++) {int u, v, w;scanf("%d%d%d",&u,&v,&w);add(u,v,w);add(v,u,w);}Dijkstra(); }?
總結(jié)
以上是生活随笔為你收集整理的【牛客 - 370B】Rinne Loves Graph(分层图最短路 或 最短路dp)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 多家银行中招,消费1元反被盗刷上万,信用
- 下一篇: spamsub.exe - spamsu