2 条题解
-
0
这道题的图可能存在负权边或负环,因此不能使用Dijkstra算法(Dijkstra算法适用于非负权图,无法处理负权边或负环)。以下是三种解法,其中前两种是基于强连通分量(SCC)缩点后在DAG上进行处理,第三种是直接对DAG进行拓扑排序和动态规划。
86.5分的Dijkstra解法
#include <bits/stdc++.h> using namespace std; const int N = 5e5 + 10; vector<int> G1[N], G2[N]; int tsp, cnt, dfn[N], low[N], scc[N], W[N]; stack<int> stk; bool instk[N]; int w[N], bar[N], dis[N]; void tarjan(int x) { dfn[x] = low[x] = ++tsp; stk.push(x); instk[x] = true; for (int y : G1[x]) { if (!dfn[y]) { tarjan(y); low[x] = min(low[x], low[y]); } else if (instk[y]) { low[x] = min(low[x], dfn[y]); } } if (dfn[x] == low[x]) { cnt++; for (int z = -1; z != x;) { z = stk.top(); stk.pop(); instk[z] = false; scc[z] = cnt; W[cnt] += w[z]; } } } int main() { int n, m; scanf("%d%d", &n, &m); for (int i = 1, x, y; i <= m; i++) { scanf("%d%d", &x, &y); G1[x].push_back(y); } for (int i = 1; i <= n; i++) scanf("%d", &w[i]); int st, p; scanf("%d%d", &st, &p); for (int i = 1; i <= p; i++) scanf("%d", &bar[i]); tsp = cnt = 0; memset(dfn, 0, sizeof(dfn)); memset(low, 0, sizeof(low)); memset(scc, 0, sizeof(scc)); memset(instk, 0, sizeof(instk)); memset(W, 0, sizeof(W)); for (int i = 1; i <= n; i++) { if (!dfn[i]) tarjan(i); } map<pair<int, int>, bool> mp; for (int i = 1; i <= n; i++) { for (int j : G1[i]) { int x = scc[i], y = scc[j]; if (x != y && !mp[{x, y}]) { G2[x].push_back(y); mp[{x, y}] = 1; } } } st = scc[st]; vector<int> dis(cnt + 1); dis[st] = W[st]; vector<bool> vis(cnt + 1); priority_queue<pair<int, int>, vector<pair<int, int>>, less<pair<int, int>>> q; q.push({dis[st], st}); while (!q.empty()) { int x = q.top().second; q.pop(); if (vis[x]) continue; vis[x] = 1; for (int y : G2[x]) { if (dis[y] < dis[x] + W[y]) { dis[y] = dis[x] + W[y]; q.push({dis[y], y}); } } } int ans = 0; for (int i = 1; i <= p; i++) { ans = max(ans, dis[scc[bar[i]]]); } printf("%d\n", ans); return 0; }100分的spfa解法
#include <bits/stdc++.h> using namespace std; const int N = 5e5 + 10; vector<int> G1[N], G2[N]; int tsp, cnt, dfn[N], low[N], scc[N], W[N]; stack<int> stk; bool instk[N]; int w[N], bar[N], dis[N]; void tarjan(int x) { dfn[x] = low[x] = ++tsp; stk.push(x); instk[x] = true; for (int y : G1[x]) { if (!dfn[y]) { tarjan(y); low[x] = min(low[x], low[y]); } else if (instk[y]) { low[x] = min(low[x], dfn[y]); } } if (dfn[x] == low[x]) { cnt++; for (int z = -1; z != x;) { z = stk.top(); stk.pop(); instk[z] = false; scc[z] = cnt; W[cnt] += w[z]; } } } int main() { int n, m; scanf("%d%d", &n, &m); for (int i = 1, x, y; i <= m; i++) { scanf("%d%d", &x, &y); G1[x].push_back(y); } for (int i = 1; i <= n; i++) scanf("%d", &w[i]); int st, p; scanf("%d%d", &st, &p); for (int i = 1; i <= p; i++) scanf("%d", &bar[i]); tsp = cnt = 0; memset(dfn, 0, sizeof(dfn)); memset(low, 0, sizeof(low)); memset(scc, 0, sizeof(scc)); memset(instk, 0, sizeof(instk)); memset(W, 0, sizeof(W)); for (int i = 1; i <= n; i++) { if (!dfn[i]) tarjan(i); } map<pair<int, int>, bool> mp; for (int i = 1; i <= n; i++) { for (int j : G1[i]) { int x = scc[i], y = scc[j]; if (x != y && !mp[{x, y}]) { G2[x].push_back(y); mp[{x, y}] = 1; } } } st = scc[st]; vector<int> dis(cnt + 1); dis[st] = W[st]; vector<bool> vis(cnt + 1); vis[st] = 1; queue<int> q; q.push(st); while (!q.empty()) { int x = q.front(); q.pop(); vis[x] = 0; for (int y : G2[x]) { if (dis[y] < dis[x] + W[y]) { dis[y] = dis[x] + W[y]; if (!vis[y]) { vis[y] = 1; q.push(y); } } } } int ans = 0; for (int i = 1; i <= p; i++) { ans = max(ans, dis[scc[bar[i]]]); } printf("%d\n", ans); return 0; }100分的Toposort DAG dp解法
#include <bits/stdc++.h> using namespace std; #define ll long long #define ull unsigned long long #define INF 0x3f3f3f3f #define lowbit(x) (x & -x) #define pii pair<int, int> #define N 500010 #define M 1000010 namespace graph { int head[N], nxt[M], to[M], rh[N]; int cnt_edge; inline void connect_head(const int &x, const int &y, int *h = head) { ++cnt_edge; nxt[cnt_edge] = h[x]; to[cnt_edge] = y; h[x] = cnt_edge; } } using namespace graph; int n, m; int dfn[N], low[N], dfc; int sta[N], *top; bool ins[N]; int bel[N], cnt, u, v; ll s[N]; // 每个scc的总和 int ind[N], tmp, p, sn; ll a[N]; ll dp[N], ans; int q[N], *front, *tail; bool b[N]; // 有酒吧 bool bn[N]; bool used[N]; // 经过s得到的点可以有used void tarjan(const int &x) { dfn[x] = low[x] = ++dfc; ins[x] = 1; *(++top) = x; for (int edg = head[x]; edg; edg = nxt[edg]) { if (!dfn[to[edg]]) { tarjan(to[edg]); low[x] = min(low[x], low[to[edg]]); } else if (ins[to[edg]]) { low[x] = min(low[x], dfn[to[edg]]); } } if (dfn[x] != low[x]) return; int last = 0; ++cnt; while (last != x) { // 出栈直到x last = *top; --top; bel[last] = cnt; s[cnt] += a[last]; ins[last] = 0; } } void input() { scanf("%d%d", &n, &m); cnt_edge = 0; memset(head, 0, sizeof(head)); for (int i = 0; i < m; i++) { scanf("%d%d", &u, &v); connect_head(u, v); } top = sta; for (int i = 1; i <= n; i++) scanf("%lld", a + i); scanf("%d%d", &sn, &p); memset(b, 0, sizeof(b)); for (int i = 1; i <= p; i++) { scanf("%d", &tmp); b[tmp] = 1; } } void solve() { dfc = cnt = 0; memset(dfn, 0, sizeof(dfn)); memset(low, 0, sizeof(low)); memset(ins, 0, sizeof(ins)); memset(bel, 0, sizeof(bel)); memset(s, 0, sizeof(s)); for (int i = 1; i <= n; i++) { if (!dfn[i]) tarjan(i); } // 建立DAG memset(ind, 0, sizeof(ind)); cnt_edge = 0; memset(rh, 0, sizeof(rh)); memset(bn, 0, sizeof(bn)); for (int i = 1; i <= n; i++) { if (b[i]) bn[bel[i]] = 1; for (int edg = head[i]; edg; edg = nxt[edg]) { int x = bel[i], y = bel[to[edg]]; if (x == y) continue; ++ind[y]; connect_head(x, y, rh); } } // DAG拓扑排序+dp front = tail = q; memset(dp, 0, sizeof(dp)); memset(used, 0, sizeof(used)); ans = 0; for (int i = 1; i <= cnt; i++) { if (!ind[i]) { *(tail++) = i; } } used[bel[sn]] = true; dp[bel[sn]] = s[bel[sn]]; while (front != tail) { int x = *front++; if (bn[x]) ans = max(ans, dp[x]); for (int edg = rh[x]; edg; edg = nxt[edg]) { int y = to[edg]; if (used[x]) { used[y] = true; dp[y] = max(dp[y], dp[x] + s[y]); } if (--ind[y] == 0) { *(tail++) = y; } } } } void output() { printf("%lld\n", ans); } int main() { input(); solve(); output(); return 0; } -
0
这道题要想清楚为什么不能用Dijkstra?
86.5分的Dijkstra:#include<bits/stdc++.h> using namespace std; const int N=5e5+10; vector<int>G1[N],G2[N]; int tsp,cnt,dfn[N],low[N],scc[N],W[N]; stack<int>stk;bool instk[N]; int w[N],bar[N],dis[N]; void tarjan(int x) { dfn[x]=low[x]=++tsp; stk.push(x);instk[x]=True; for(int y:G1[x]) { if(!dfn[y]) { tarjan(y); low[x]=min(low[x],low[y]); } else if(instk[y])low[x]=min(low[x],dfn[y]); } if(dfn[x]==low[x]) { cnt++; for(int z=-1;z!=x;) { z=stk.top();stk.pop();instk[z]=False; scc[z]=cnt;W[cnt]+=w[z]; } } } int main() { int n,m;scanf("%d%d",&n,&m); for(int i=1,x,y;i<=m;i++)scanf("%d%d",&x,&y),G1[x].push_back(y); for(int i=1;i<=n;i++) scanf("%d",&w[i]); int st,p;scanf("%d%d",&st,&p); for(int i=1;i<=p;i++) scanf("%d",&bar[i]); tsp=cnt=0;memset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low)); memset(scc,0,sizeof(scc));memset(instk,0,sizeof(instk)); memset(W,0,sizeof(W)); for(int i=1;i<=n;i++)if(!dfn[i])tarjan(i); map<pair<int,int>,bool>mp; for(int i=1;i<=n;i++)for(int j:G1[i]) { int x=scc[i],y=scc[j]; if(x!=y && !mp[{x,y}])G2[x].push_back(y),mp[{x,y}]=1; } st=scc[st]; vector<int>dis(cnt+1);dis[st]=W[st]; vector<bool>vis(cnt+1); priority_queue<pair<int,int>,vector<pair<int,int>>,less<pair<int,int>> >q;q.push({dis[st],st}); while(!q.empty()) { int x=q.top().second;q.pop();if(vis[x]==1)continue; vis[x]=1; for(int y:G2[x]) { if(dis[y]<dis[x]+W[y]) { dis[y]=dis[x]+W[y]; q.push({dis[y],y}); } } } int ans=0; for(int i=1;i<=p;i++)ans=max(ans,dis[scc[bar[i]]]); printf("%d\n",ans); return 0; }
100分的spfa:#include<bits/stdc++.h> using namespace std; const int N=5e5+10; vector<int>G1[N],G2[N]; int tsp,cnt,dfn[N],low[N],scc[N],W[N]; stack<int>stk;bool instk[N]; int w[N],bar[N],dis[N];
void tarjan(int x) { dfn[x]=low[x]=++tsp; stk.push(x);instk[x]=True; for(int y:G1[x]) { if(!dfn[y]) { tarjan(y); low[x]=min(low[x],low[y]); } else if(instk[y])low[x]=min(low[x],dfn[y]); } if(dfn[x]==low[x]) { cnt++; for(int z=-1;z!=x;) { z=stk.top();stk.pop();instk[z]=False; scc[z]=cnt;W[cnt]+=w[z]; } } }
int main() { int n,m;scanf("%d%d",&n,&m); for(int i=1,x,y;i<=m;i++)scanf("%d%d",&x,&y),G1[x].push_back(y); for(int i=1;i<=n;i++) scanf("%d",&w[i]); int st,p;scanf("%d%d",&st,&p); for(int i=1;i<=p;i++) scanf("%d",&bar[i]);
tsp=cnt=0;memset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low)); memset(scc,0,sizeof(scc));memset(instk,0,sizeof(instk)); memset(W,0,sizeof(W)); for(int i=1;i<=n;i++)if(!dfn[i])tarjan(i); map<pair<int,int>,bool>mp; for(int i=1;i<=n;i++)for(int j:G1[i]) { int x=scc[i],y=scc[j]; if(x!=y && !mp[{x,y}])G2[x].push_back(y),mp[{x,y}]=1; } st=scc[st]; vector<int>dis(cnt+1);dis[st]=W[st]; vector<bool>vis(cnt+1);vis[st]=1; queue<int>q;q.push(st); while(!q.empty()) { int x=q.front();q.pop();vis[x]=0; for(int y:G2[x]) { if(dis[y]<dis[x]+W[y]) { dis[y]=dis[x]+W[y]; if(!vis[y])q.push(y),vis[y]=1; } } } int ans=0; for(int i=1;i<=p;i++)ans=max(ans,dis[scc[bar[i]]]); printf("%d\n",ans); return 0;}
100 分的 Toposort DAG dp:</p>#include<bits/stdc++.h> using namespace std; #define ll long long #define ull unsigned long long #define INF 0x3f3f3f3f #define lowbit(x) (x&-x) #define pii pair<int,int> #define N 500010 #define M 1000010 namespace graph{ int head[N],nxt[M],to[M],rh[N]; int cnt_edge; inline void connect_head(const int &x,const int &y,int *h = head){ ++cnt_edge; nxt[cnt_edge] = h[x]; to[cnt_edge] = y; h[x] = cnt_edge; } } using namespace graph; int n,m; int dfn[N],low[N],dfc; int sta[N],*top; bool ins[N]; int bel[N],cnt,u,v; ll s[N];// 每个 scc 的总和 int ind[N],tmp,p,sn; ll a[N]; ll dp[N],ans; int q[N],*front,*tail; bool b[N];// 有酒吧 bool bn[N]; bool used[N];// 经过 s 得到的点可以有 used void tarjan(const int &x){ dfn[x] = low[x] = ++dfc; ins[x] = 1; *(++top) = x; for(int edg = head[x];edg;edg = nxt[edg]){ if(!dfn[to[edg]]){ tarjan(to[edg]); low[x] = min(low[x],low[to[edg]]); }else if(ins[to[edg]])low[x] = min(low[x],dfn[to[edg]]); } if(dfn[x] != low[x])return ; int last = 0; ++cnt; while(last != x){ last = *top; --top; bel[last] = cnt; s[cnt] += a[last]; ins[last] = 0; } } // 输入函数 void input(){ scanf("%d%d",&n,&m); while(m--){ scanf("%d%d",&u,&v); connect_head(u,v); } top = sta; for(int i = 1;i <= n;++i)scanf("%lld",a+i); scanf("%d%d",&sn,&p); for(int i = 1;i <= p;++i){ scanf("%d",&tmp); b[tmp] = 1; } } // 处理函数 void solve(){ for(int i = 1;i <= n;++i)if(!dfn[i])tarjan(i); // 建立 dag for(int i = 1;i <= n;++i){ if(b[i])bn[bel[i]] = 1; for(int edg = head[i];edg;edg = nxt[edg]){ if(bel[i] == bel[to[edg]])continue; ++ind[bel[to[edg]]]; connect_head(bel[i],bel[to[edg]],rh); } } // dagdp front = tail = q; for(int i = 1;i <= cnt;++i)if(!ind[i])*(tail++) = i; used[bel[sn]] = 1; int x; while(front != tail){ x = *front; ++front; if(used[x])dp[x] += s[x]; // printf("x = %d used = %d b = %d dp = %lld\n",x,used[x],bn[x],dp[x]); if(bn[x])ans = max(dp[x],ans); for(int edg = rh[x];edg;edg = nxt[edg]){ --ind[to[edg]]; if(used[x]){ used[to[edg]] = 1; dp[to[edg]] = max(dp[to[edg]],dp[x]); } if(!ind[to[edg]])*(tail++) = to[edg]; } } } // 输出函数 void output(){ printf("%lld",ans); } // 主函数 int main(){ input(); solve(); output(); return 0; }
- 1
信息
- ID
- 2832
- 时间
- 5000ms
- 内存
- 256MiB
- 难度
- 8
- 标签
- 递交数
- 148
- 已通过
- 20
- 上传者