A【转自:https://www.cnblogs.com/MengX/p/9762274.html】
题目 Jzzhu and Cities
链接 http://codeforces.com/contest/449/problem/B
题意:给出n个点m条公路k条铁路。
接下来m行 u v w u->v 距离w
然后k行 v w 1->v 距离w
如果修建了铁路并不影响两点的最短距离,那么修铁路是没必要的
求能删掉多少条铁路
思路:
我们把先按照公路和铁路建图,1到铁路v的距离小于w显然这条铁路是没有必要,或者1到铁路重点v距离有多个等于w及度>1 我们也可以删掉这条铁路
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define fio ios_base::sync_with_stdio(false),cin.tie(0); 4 #define Pii pair<int,int> 5 #define INF 0x3f3f3f3f3f3f3f3f 6 #define ll long long 7 const int maxn = 100005; 8 ll dis[maxn]; 9 int head[maxn],To[maxn*20],Len[maxn*20],Next[maxn*20],cnt; 10 int vis[maxn],x[maxn],y[maxn],in[maxn]; 11 void add(int u,int v,int w) 12 { 13 Next[++cnt]=head[u]; 14 head[u]=cnt; 15 To[cnt]=v; 16 Len[cnt]=w; 17 } 18 int k,n,m; 19 priority_queue<Pii,vector<Pii> , greater<Pii> > q; 20 int dij() 21 { 22 dis[1]=0; 23 q.push(Pii(0,1)); 24 while(!q.empty()) 25 { 26 Pii tmp=q.top(); 27 int u=tmp.second; 28 q.pop(); 29 if(vis[u]) continue; 30 vis[u]=1; 31 for(int i=head[u]; i!=-1; i=Next[i]) 32 { 33 int v=To[i]; 34 int d=Len[i]; 35 if(dis[v]>dis[u]+d) 36 { 37 in[v]=1; 38 dis[v]=dis[u]+d; 39 q.push(Pii(dis[v],v)); 40 } 41 else if(dis[v]==dis[u]+d) 42 in[v]++; 43 } 44 } 45 int ans=0; 46 for(int i=1; i<=k; i++) 47 { 48 if(dis[x[i]]<y[i]) ans++; 49 else 50 { 51 if(dis[x[i]]==y[i]&&in[x[i]]>1) 52 { 53 in[x[i]]--; 54 ans++; 55 } 56 } 57 } 58 return ans; 59 } 60 int main() 61 { 62 scanf("%d %d %d",&n,&m,&k); 63 for(int i=0; i<=n; i++) 64 { 65 dis[i]=INF; 66 } 67 memset(head,-1,sizeof(head)); 68 for(int i=1; i<=m; i++) 69 { 70 int u,v,w; 71 scanf("%d %d %d",&u,&v,&w); 72 add(u,v,w); 73 add(v,u,w); 74 } 75 for(int i=1; i<=k; i++) 76 { 77 int v,w; 78 scanf("%d %d",&x[i],&y[i]); 79 add(1,x[i],y[i]); 80 add(x[i],1,y[i]); 81 } 82 cout<<dij()<<endl; 83 return 0;
B 【转自:https://blog.csdn.net/weixin_30270889/article/details/97425739】
题目 Planets
链接 https://codeforces.com/problemset/problem/229/B
题意 我们要找一条从1到N的最短路。现在每个点都会在一些时间关闭通道,这些时间不能在这些点上。
思路 设dis[i]表示到达i号传送器的最早时刻.显然,虽然有那么多的出发时刻的限制,但我们还是越早到越好的.因为你到得越早,出发的时间肯定不会比到达的时刻晚的差.所以,就是一个最短路的问题啦.因为数据范围比较大.所以得用dijkstra+优先队列的优化.在出去的时候,只要枚举一遍到达这个点的所有时刻,就能知道它啥时候出发了.因为∑ki<=10^5,根据dijkstra算法也能知道,每个点作为最小值更新其他点只会用到一次.所以这个枚举所有时刻的过程的复杂度是线性的,就只会枚举10^5次。
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<queue> #include<vector> #define MAX 100000+10 #define INF 0x3f3f3f3f using namespace std; int n, m; int cnt; int head[MAX]; vector<int> other[MAX]; int vis[MAX]; int dis[MAX]; struct E { int next, from, to, w; }edge[1000000]; void add(int from, int to, int w) { edge[cnt].to = to; edge[cnt].w = w; edge[cnt].next = head[from]; head[from] = cnt++; return; } int wait(int s, int time) { int t = 0; for (int i = 0; i < (int)other[s].size(); i++) { int tt = other[s][i]; if (tt < time) continue; if (tt == time) { t++; time++; } else { break; } } return t; } void SPFA(int ss) { for (int i = 1; i <= n; i++) { dis[i] = INF; } vis[ss] = 1; dis[ss] = wait(ss, 0); queue<int> Q; Q.push(ss); while (!Q.empty()) { int u = Q.front(); Q.pop(); vis[u] = 0; //注意必须是在这里算出waittime,放在下一个循环里会WA int wait_time_for_u = dis[u] + wait(u, dis[u]); for (int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].to; int w = edge[i].w; int arrive_time = wait_time_for_u + w; if (dis[v] > arrive_time) { dis[v] = arrive_time; if (!vis[v]) { vis[v] = 1; Q.push(v); } } } } } int main(void) { while (~scanf("%d%d", &n, &m)) { memset(head, -1, sizeof(head)); memset(vis, 0, sizeof(vis)); memset(other, 0, sizeof(other)); cnt = 0; for (int i = 1; i <= m; i++) { int a, b, d; scanf("%d%d%d", &a, &b, &d); add(a, b, d); add(b, a, d); } for (int i = 1; i <= n; i++) { int t, x; scanf("%d", &t); while (t--) { scanf("%d", &x); other[i].push_back(x); } } SPFA(1); if (dis[n] == INF) { printf("-1\n"); } else { printf("%d\n", dis[n]); } } return 0; }