38 条题解
-
4ToSoul LV 5 @ 2017-09-11 21:58:17
这道题的题意就不多说了,主要说下这里的两个主流做法。
1.DP:
其实这就是我最初的想法,不如让我们想想,对于一个强联通分量而言,我们想从哪里进就进,想从哪里出就出,而他们中的最小值或最大值我们是可以随便取的。当把这些强联通分量进行了缩点操作后,他们自然就变成了一个 普通的点 (只不过保存最小值和最大值),而在整个图则变成了一个 DAG 图,不难想到以 F[i](取当前城市作为出售处的最大利润) 的状态设计,然后先处理 Z[i] (从1所属的强联通点到i所属的强联通点中作为购入处的最小代价),再跑一遍 F[i] 即可。2.SPFA:
这是我从网上看到的解法,是在是佩服,对所有的有向边分别以 原方向 和 反方向 建两个图(无向边...),分别从 1点 和 N点 跑一遍 SPFA(SPFA的状态存的是经过点的最值,正向存最小值,反向存最大值,这一切目的都是为了保证购入点在卖出点前操作) ,然后枚举 交接点 ,算出两者之和的最大值即可。SPFA代码:
正反图,正反SPFA
这个还正常些...#include <queue> #include <vector> #include <cstdio> #include <cstring> #include <iostream> #define INF (0x3f3f3f3f) using namespace std; int N, M, ans; vector<int> E1[100005], E2[100005]; int A[100005], B[100005], C[100005], V[100005]; void SPFA1 () { queue<int> Q; Q.push(1); memset(V, 0, sizeof(V)); memset(B, INF, sizeof(B)); V[1]=1; while(!Q.empty()) { int x=Q.front(); Q.pop(); B[x]=min(B[x], A[x]); for(int i=0; i<E1[x].size(); i++) { int v=E1[x][i]; if (B[x]<B[v]) { B[v]=B[x]; if (!V[v]) { V[v]=1; Q.push(v); } } } V[x]=0; } } void SPFA2 () { queue<int> Q; Q.push(N); memset(V, 0, sizeof(V)); memset(C, 0, sizeof(C)); V[N]=1; while(!Q.empty()) { int x=Q.front(); Q.pop(); C[x]=max(C[x], A[x]); for(int i=0; i<E2[x].size(); i++) { int v=E2[x][i]; if (C[x]>C[v]) { C[v]=C[x]; if (!V[v]) { V[v]=1; Q.push(v); } } } V[x]=0; } } int main () { ios::sync_with_stdio(false); cin >> N >> M; for(int i=1; i<=N; i++) cin >> A[i]; int u, v, k; for(int i=1; i<=M; i++) { cin >> u >> v >> k; E1[u].push_back(v); E2[v].push_back(u); if (k>1) { E1[v].push_back(u); E2[u].push_back(v); } } SPFA1(); SPFA2(); for(int i=1; i<=N; i++) ans=max(ans, C[i]-B[i]); cout << ans; return 0; }
DP代码:
Tarjan缩点+Dp
DP我是用SPFA跑的,我跑BFS要挂...#include <stack> #include <queue> #include <vector> #include <cstdio> #include <cstring> #include <iostream> #define INF (0x3f3f3f3f) using namespace std; int N, M, G, H; stack<int> S; vector<int> E1[100005], E2[100005]; int A[100005], F[100005], Z[100005], X[100005], C[100005], D[100005], L[100005], V[100005]; void DP () { queue<int> Q; Q.push(C[1]); memset(V, 0, sizeof(V)); V[C[1]]=1; memset(F, -INF, sizeof(F)); F[C[1]]=0; while(!Q.empty()) { int x=Q.front(); Q.pop(); F[x]=max(F[x], X[x]-Z[x]); for(int i=0; i<E2[x].size(); i++) { int v=E2[x][i]; if (Z[v]>Z[x]||F[v]<F[x]) { Z[v]=min(Z[v], Z[x]); F[v]=max(F[v], F[x]); if (!V[v]) { V[v]=1; Q.push(v); } } } V[x]=0; } } void TARJAN (int x){ D[x]=L[x]=++G; V[x]=1; S.push(x); for(int i=0; i<E1[x].size(); i++) { int v=E1[x][i]; if (!D[v]) { TARJAN(v); L[x]=min(L[x], L[v]); } else if (V[v]) L[x]=min(L[x], D[v]); } if (D[x]==L[x]) { C[x]=++H; V[x]=0; while(x!=S.top()) { C[S.top()]=H; V[S.top()]=0; S.pop(); } S.pop(); } } int main () { ios::sync_with_stdio(false); cin >> N >> M; for(int i=1; i<=N; i++) cin >> A[i]; int u, v, k; for(int i=1; i<=M; i++) { cin >> u >> v >> k; E1[u].push_back(v); if (k>1) E1[v].push_back(u); } for(int i=1; i<=N; i++) if (!D[i]) TARJAN(i); for(int i=1; i<=N; i++) for(int j=0; j<E1[i].size(); j++) { int v=E1[i][j]; if (C[i]!=C[v]) E2[C[i]].push_back(C[v]); } memset(Z, INF, sizeof(Z)); memset(X, 0, sizeof(X)); for(int i=1; i<=N; i++) { Z[C[i]]=min(Z[C[i]], A[i]); X[C[i]]=max(X[C[i]], A[i]); } DP(); cout << F[C[N]]; return 0; }
-
12018-09-09 11:35:22@
不带任何高级技巧的搜索+乱搞哈希
适合蒟蒻阅读
First:
我不会链式前向星,但是邻接矩阵肯定会爆,所以用了很神奇的结构体存图
struct point{ int val; int tox;//点的出度 int to[500];//所连接的点数组 }q[100000];
只存了最多500个点,怕爆空间,可以水过。
Second:
搜索的时候用一个sta变量表示阶段。
通过阅读可得,贸易可以分为三个阶段:
买珠宝、卖珠宝、去终点
由于三个阶段是顺序做的事情,所以可以分别搜索
最后关于判重:乱搞哈希
我搜索时用到的三个变量:现在所在的地点now,拥有的钱money,以及现处阶段sta。于是就乱搞了这个判重语句:
int hash(int a,int b,int c) { return (a*133%MOD+b*97%MOD+c*17%MOD)%MOD; }//哈希函数 void dfs(int now,int money,int sta) { int ha=hash(now,money,sta); if(HASH[ha]) return ; HASH[ha]=true; ...... }
#完整AC程序
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; struct point{ int val; int tox; int to[500]; }q[100000]; int i,n,m,ans; int MOD=9999990; bool HASH[9999990];//哈希判重 void add(int x,int y) { q[x].tox++;q[x].to[q[x].tox]=y; } int has(int a,int b,int c) { return (a*133%MOD+b*97%MOD+c*17%MOD)%MOD; } void dfs(int now,int money,int sta) { int j,k; int ha=has(now,money,sta); if(HASH[ha]) return ; HASH[ha]=true; if(now==n&&sta==3) { if(money>ans) ans=money; return ; }//到达终点 if(sta==1) { for(j=1;j<=q[now].tox;j++) { //在这里买 dfs(q[now].to[j],q[now].val,2); //不在这里买 dfs(q[now].to[j],money,1); } } else if(sta==2) //卖 { for(j=1;j<=q[now].tox;j++) { //在这里卖 if(q[now].val-money>ans) dfs(q[now].to[j],q[now].val-money,3); //不卖 dfs(q[now].to[j],money,2); } } else { for(j=1;j<=q[now].tox;j++) dfs(q[now].to[j],money,3); }//去终点 return ; } int main() { cin>>n>>m; for(i=1;i<=n;i++) cin>>q[i].val; for(i=1;i<=m;i++) { int x,y,z; cin>>x>>y>>z; add(x,y); if(z==2) add(y,x); } dfs(1,0,1); cout<<ans; }
-
12018-08-23 13:08:43@
tarjan缩点成为DAG图,然后记忆化搜索
#include<bits/stdc++.h> using namespace std; const int maxn=100004,maxm=500004; int n,m,cnt=0,dep=0,sum=0; stack<int>s; int ans[maxn],dp[maxn][2],price[maxn],head[maxn<<1],dfn[maxn],low[maxn],vis[maxn],col[maxn],maxx[maxn],minn[maxn]; struct node{ int to,next; }e[maxm<<2]; void add(int u,int v){ e[++cnt].to=v;e[cnt].next=head[u];head[u]=cnt; } void tarjan(int u){ dfn[u]=low[u]=++dep; vis[u]=1; s.push(u); for(int i=head[u];i;i=e[i].next){ int v=e[i].to; if(!dfn[v]){ tarjan(v); low[u]=min(low[u],low[v]); }else if(vis[v]) low[u]=min(low[u],dfn[v]); } if(dfn[u]==low[u]){ col[u]=++sum;vis[u]=0; maxx[sum]=minn[sum]=price[u]; while(1){ int x=s.top();s.pop();vis[x]=0; col[x]=sum; maxx[sum]=max(maxx[sum],price[x]); minn[sum]=min(minn[sum],price[x]); if(x==u) break; } } } void shrink_point(){ for(int i=1;i<=n;i++){ for(int j=head[i];j;j=e[j].next){ int v=e[j].to; if(col[v]==col[i]) continue; add(col[v]+n,col[i]+n); } } } void dfs(int u){ if(dp[u][0]) return; dp[u][0]=maxx[u],dp[u][1]=minn[u]; for(int i=head[u+n];i;i=e[i].next){ int v=e[i].to; v-=n; dfs(v); ans[u]=max(ans[u],ans[v]); dp[u][1]=min(dp[u][1],dp[v][1]); } ans[u]=max(ans[u],dp[u][0]-dp[u][1]); } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&price[i]); for(int i=1;i<=m;i++){ int x,y,z; scanf("%d%d%d",&x,&y,&z); if(z==1) add(x,y); else {add(x,y);add(y,x);} } for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i); shrink_point(); dp[col[1]][0]=maxx[col[1]],dp[col[1]][1]=minn[col[1]]; ans[col[1]]=maxx[col[1]]-minn[col[1]]; dfs(col[n]); printf("%d",ans[col[n]]); }
-
12018-07-06 14:17:42@
看了一下题解区。。。没发现用C的,我先来一发~
正向spfa+反向bfs==AC#define _USE_MATH_DEFINES #include <stdio.h> #include <math.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <stdbool.h> #include <float.h> #include <limits.h> #include <malloc.h> #include <memory.h> #include <complex.h> #include <errno.h> #include <time.h> #include <assert.h> #define Swap(X,Y) ((X)=(X)^(Y),(Y)=(X)^(Y),(X)=(X)^(Y)) #define Max(X,Y) ((X)>(Y) ? (X) : (Y)) #define Min(X,Y) ((X)<(Y) ? (X) : (Y)) #define EPS 1e-7 #define MOD 998244353 #define M 500005 #define N 100005 int n,m,i,a[M],b[M],c[N],e[M],r[N],rr[N],*g[N],*gg[N],d[N<<1],f[N], max,op,ed,dis[N]; void spfa(int x) { int i; memset(dis,127/3,sizeof(dis)); memset(f,0,sizeof(f)); op=0; ed=f[x]=1; d[1]=x; dis[x]=c[x]; while (op!=ed) { op=op>2*n+1 ? 1 : ++op; f[d[op]]=0; for (i=1;i<=r[d[op]];i++) if (dis[g[d[op]][i]]>dis[d[op]]) { dis[g[d[op]][i]]=Min(dis[d[op]],c[g[d[op]][i]]); if (!f[g[d[op]][i]]) { ed=ed>2*n+1 ? 1 : ++ed; d[ed]=g[d[op]][i]; f[d[ed]]=1; } } } } void bfs(int x) { int i; memset(f,0,sizeof(f)); op=ed=f[x]=1; d[1]=x; while (op<=ed) { for (i=1;i<=rr[d[op]];i++) if (!f[gg[d[op]][i]]) { d[++ed]=gg[d[op]][i]; f[d[ed]]=1; } op++; } } int main() { memset(r,0,sizeof(r)); memset(rr,0,sizeof(rr)); scanf("%d %d",&n,&m); for (i=1;i<=n;i++) scanf("%d",&c[i]); for (i=1;i<=m;i++) { scanf("%d %d %d",&a[i],&b[i],&e[i]); if (e[i]&1) { r[a[i]]++; rr[b[i]]++; } else { r[a[i]]++; r[b[i]]++; rr[a[i]]++; rr[b[i]]++; } } for (i=1;i<=n;i++) { g[i]=(int *) malloc((r[i]+1)*sizeof(int)); gg[i]=(int *) malloc((rr[i]+1)*sizeof(int)); } memset(r,0,sizeof(r)); memset(rr,0,sizeof(rr)); for (i=1;i<=m;i++) if (e[i]&1) { g[a[i]][++r[a[i]]]=b[i]; gg[b[i]][++rr[b[i]]]=a[i]; } else { g[a[i]][++r[a[i]]]=b[i]; g[b[i]][++r[b[i]]]=a[i]; gg[a[i]][++rr[a[i]]]=b[i]; gg[b[i]][++rr[b[i]]]=a[i]; } spfa(1); bfs(n); for (i=1,max=INT_MIN;i<=ed;i++) max=Max(max,c[d[i]]-dis[d[i]]); printf("%d\n",max); return 0; }
May the father of understanding guide U !
-
12018-02-10 21:27:58@
题目大意:
给你一个图,他又n个点和m条边。这些边可能是双向的也可能是单向的。先在,你要从1号点出发,要你到n号点上去,且不能经过所有点。每个点可以经过多次。现在,由于你知道了每个点上的水晶球的价格是不相同的,所以你要去做一次买卖:在一个点
上买进一个水晶球且在另一个点上卖出那个水晶球。他要求买卖获得的差价最高是多少。题解思路:
输入的存法:v[i][j]表示第i个点的第j条路线的另外一个端点。
u[i]j表示第j条能到达i号点的路的另外一个端点。先用一个接近与SPFA和BFS的东西来预处理出从一号点到x号点这条路径上能所买到的水晶球的最低价格,用dis[x]来存。弄完以后,我们有DFS来找:找过的就return,没找过就取做大值max(ans,a[x]-dis[x]);
最后输出ans程序:
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <float.h>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <set>
#include <queue>
#include <limits>
#include <deque>
#include <locale>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <wchar.h>
#include <wctype.h>
#include <algorithm>
#include <bitset>
#include <map>
#include <iomanip>
#include <ios>
#include <iostream>
#include <vector>
#include <cwchar>
#include <cwctype>
#define mp make_pair
#define fs first
#define se second
#define memset(a,t) memset(a,t,sizeof(a))
#define all(v) v.begin(),v.end()
#define eprintf(...) fprintf(stderr, VA_ARGS),fflush(stderr)
#define MN 0LL
#define Mx 200000005
#define Mn -Mx
#define MX 20000000000000005
using namespace std;
int readint(){
char c;
while(c=getchar(),(c<'0'||c>'9')&&c!='-');
bool flag=(c=='-');
if(flag)c=getchar();
int x=0;
while(c>='0'&&c<='9'){
x=x*10+c-48;
c=getchar();
}
return flag?-x:x;
}
inline string tos(int x){
string s;
while(x) s=(char)(x%10+'0')+s,x/=10;
return s;
}
int n,m;
int a[100005];
vector<int> v[100005];
vector<int> u[100005];
int dis[100005];
queue<int> q;
int ans=0;
bool vd[100005];
inline void dfs(int x){
if(vd[x]) return;
vd[x]=1;
ans=max(ans,(a[x]-dis[x]));
for(int i=0;i<u[x].size();i++){
dfs(u[x][i]);
}
}
int main(){
int i,j,x,y,z,p;
cin>>n>>m;
for(i=0;i<n;i++) cin>>a[i];
for(i=0;i<m;i++){
cin>>x>>y>>z;
x--,y--,z--;
v[x].push_back(y);
u[y].push_back(x);
if(z) v[y].push_back(x),u[x].push_back(y);
}
memset(dis,63);
dis[0]=a[0];
q.push(0);
while(!q.empty()){
p=q.front();
q.pop();
dis[p]=min(dis[p],a[p]);
for(i=0;i<v[p].size();i++){
x=v[p][i];
if(dis[x]>dis[p]){
dis[x]=dis[p];
q.push(x);
}
}
}
// for(i=0;i<n;i++) cout<<dis[i]<<' ';
// cout<<endl;
dfs(n-1);
cout<<ans<<endl;
return 0;}
-
02018-07-06 16:33:13@
反向DFS+正向DFS(深搜的点能够达到n)=AC
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; struct kk{ int f,t,pre; }edge1[500010],edge2[500010]; int dist1[100010],dist2[100010],v[100010],num,ans,i,j,z,y,x,m,n,next1[100010],next2[100010]; bool vis1[100010],vis2[100010]; void dfs2(int x) { int i; for (i=next2[x];i>0;i=edge2[i].pre) { if (vis2[edge2[i].t]==false) { vis2[edge2[i].t]=true; dist2[edge2[i].t]=max(v[edge2[i].t],dist2[edge2[i].f]); dfs2(edge2[i].t); } } } void dfs1(int x) { int i; for (i=next1[x];i>0;i=edge1[i].pre) { if (vis1[edge1[i].t]==false && vis2[edge2[i].t]==true) { vis1[edge1[i].t]=true; dist1[edge1[i].t]=min(v[edge1[i].t],dist1[edge1[i].f]); dfs1(edge1[i].t); } } } int main() { scanf("%d%d",&n,&m); num=0; ans=0; for (i=1;i<=n;++i) scanf("%d",&v[i]); for (i=1;i<=m;++i) { scanf("%d%d%d",&x,&y,&z); edge1[++num].f=x; edge1[num].t=y; edge1[num].pre=next1[x]; next1[x]=num; edge2[num].f=y; edge2[num].t=x; edge2[num].pre=next2[y]; next2[y]=num; if (z==2) { edge1[++num].f=y; edge1[num].t=x; edge1[num].pre=next1[y]; next1[y]=num; edge2[num].f=x; edge2[num].t=y; edge2[num].pre=next2[x]; next2[x]=num; } } dist2[n]=v[n]; dist1[1]=v[1]; dfs2(n); dfs1(1); for (i=1;i<=n;++i) ans=max(ans,dist2[i]-dist1[i]); printf("%d",ans); }
-
02018-02-11 21:58:12@
呵呵呵~~想了1小时没想出来,后来无意中看到了SPFA4个字母,就AC了~~!
-
02017-10-27 16:44:25@
SPFA*2
#include <bits/stdc++.h> using namespace std; int n,m,ss,maxx,minn=1000,ans=0; dis[100001]; diss[100001]; int pri[100001]; bool used[100001]; struct edge { int u; edge *next; } e[1000002],*p=e,*point[100001]; struct edge1 { int u; edge1 *next; } e1[1000002],*p1=e1,*point1[100001]; queue<int>q; inline void add(int x,int y) { p++; p->u=y; p->next=point[x]; point[x]=p; } inline void add1(int x,int y) { p1++; p1->u=y; p1->next=point1[x]; point1[x]=p1; } void spfa() { memset(dis,127,sizeof(dis)); memset(used,0,sizeof(used)); q.push(ss); used[ss]=1; while(!q.empty()) { int s=q.front(); q.pop(); used[s]=0; dis[s]=min(dis[s],pri[s]); for(p=point[s];p;p=p->next) { if(dis[s]<dis[p->u]) { dis[p->u]=dis[s]; if(!used[p->u]) { used[p->u]=1; q.push(p->u); } } } } return; } void Spfa() { memset(diss,0,sizeof(diss)); memset(used,0,sizeof(used)); q.push(ss); used[ss]=1; while(!q.empty()) { int s=q.front(); q.pop(); used[s]=0; diss[s]=max(pri[s],diss[s]); for(p1=point1[s];p1;p1=p1->next) { if(diss[s]>diss[p1->u]) { diss[p1->u]=diss[s]; if(!used[p1->u]) { used[p1->u]=1; q.push(p1->u); } } } } return; } int main() { // freopen("trade.in","r",stdin); // freopen("trade.out","w",stdout); int z,x,y; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&pri[i]); } for(int i=1;i<=m;i++) { scanf("%d%d%d",&x,&y,&z); add(x,y); add1(y,x); if(z==2) { add(y,x); add1(x,y); } } ss=1; spfa(); ss=n; Spfa(); for(int i=1;i<=n;i++) { ans=max(ans,diss[i]-dis[i]); } printf("%d",ans); return 0; }
-
02017-10-24 21:58:49@
#include <stdio.h> #include <algorithm> #include <stack> #include <string.h> using namespace std; const int MAXN=1e5+5; const int MAXM=5e5+5; const int INF=0x7f7f7f7f; struct Edge{ int v,next; }E[MAXM<<1]; int head[MAXN],Ecnt; int w[MAXN]; int n,m; void add(int u,int v){ E[++Ecnt]=(Edge){v,head[u]};head[u]=Ecnt; } int low[MAXN],dfn[MAXN],idx; int in[MAXN]; stack<int>sta; int MAX[MAXN],MIN[MAXN]; int belong[MAXN]; int Bcnt; void tarjan(int u){ low[u]=dfn[u]=++idx; in[u]=1; int v; sta.push(u); for(int i=head[u];i;i=E[i].next){ v=E[i].v; if(!dfn[v]) tarjan(v),low[u]=min(low[u],low[v]); else if(in[v]) low[u]=min(low[u],dfn[v]); } if(low[u]==dfn[u]){ Bcnt++; do{ v=sta.top(); sta.pop(); in[v]=0; belong[v]=Bcnt; MAX[Bcnt]=max(MAX[Bcnt],w[v]); MIN[Bcnt]=min(MIN[Bcnt],w[v]); }while(u!=v); } } int f[MAXM],t[MAXM]; int dp[MAXN]; int ans; int vis[MAXN]; void dfs(int u){ if(u==belong[n]) dp[u]=max(dp[u],MAX[u]); for(int i=head[u];i;i=E[i].next){ int v=E[i].v; if(!vis[v]) dfs(v),vis[v]=1; dp[u]=max(dp[u],dp[v]); } if(dp[u]) dp[u]=max(dp[u],MAX[u]); ans=max(ans,dp[u]-MIN[u]); } void solve(){ memset(MIN,INF,sizeof MIN); for(int i=1;i<=n;i++){ if(!dfn[i]) tarjan(i); } Ecnt=0; memset(head,0,sizeof head); for(int i=1;i<=m;i++){ int pu=belong[f[i]]; int pv=belong[t[i]]; if(pu==pv) continue; add(pu,pv); } vis[belong[1]]=1; dfs(belong[1]); printf("%d",ans); } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ scanf("%d",&w[i]); } for(int i=1;i<=m;i++){ int u,v,op; scanf("%d%d%d",&u,&v,&op); f[i]=u;t[i]=v; if(op==1) add(u,v); else add(u,v),add(v,u); } solve(); return 0; }
-
02016-04-11 18:54:28@
评测结果
编译成功
测试数据 #0: Accepted, time = 0 ms, mem = 11892 KiB, score = 10
测试数据 #1: Accepted, time = 0 ms, mem = 11892 KiB, score = 10
测试数据 #2: Accepted, time = 15 ms, mem = 11888 KiB, score = 10
测试数据 #3: Accepted, time = 93 ms, mem = 11924 KiB, score = 10
测试数据 #4: Accepted, time = 109 ms, mem = 11988 KiB, score = 10
测试数据 #5: Accepted, time = 0 ms, mem = 11888 KiB, score = 10
测试数据 #6: Accepted, time = 15 ms, mem = 11892 KiB, score = 10
测试数据 #7: Accepted, time = 46 ms, mem = 11920 KiB, score = 10
测试数据 #8: Accepted, time = 140 ms, mem = 11996 KiB, score = 10
测试数据 #9: Accepted, time = 109 ms, mem = 11984 KiB, score = 10
Accepted, time = 527 ms, mem = 11996 KiB, score = 100
代码//正向SPFA 获得最小 买入价格
//反向SPFA 获得最大 卖出价格#include <cstdio>
#include <queue>//#define debug
using std::queue;
struct edge{
int d;
struct edge *link;
};int top=1,n,m;
int price[100010];
edge graph[100010]={0};
edge graph2[100010]={0};
edge node[500050*2];void read(int s,int d){
edge *l;
l=&node[top];
l->d=d;
l->link=graph[s].link;
graph[s].link=l;
top++;
}void read2(int s,int d){
edge *l;
l=&node[top];
l->d=d;
l->link=graph2[s].link;
graph2[s].link=l;
top++;
}void build(){
scanf("%d%d",&n,&m);
int s,d,z;
for(int i=1;i<=n;i++)
scanf("%d",&price[i]);for(int i=1;i<=m;i++){
scanf("%d%d%d",&s,&d,&z);
read(s,d);
read2(d,s);
if(z==2){
read(d,s);
read2(s,d);
}
}
}//SPFA
int inque[100010]={0};
int dist[100010];
queue <int> q;void spfa(int s){
for(int i=1;i<=n;i++)
dist[i]=9999;
q.push(s);
inque[s]=1;
dist[s]=price[s];
edge *l;
int t;
while(!q.empty()){
t=q.front();
q.pop();
inque[t]=0;
l=graph[t].link;
int minthis;
while(l){
minthis=dist[t]<price[l->d]?dist[t]:price[l->d];
if(minthis<dist[l->d]){
dist[l->d]=minthis;if(!inque[l->d]){
q.push(l->d);
inque[l->d]=1;
}
}
l=l->link;
}
}
}int dist2[100010];
void spfa2(int s){
for(int i=1;i<=n;i++)
dist2[i]=-9999;
q.push(s);
inque[s]=1;
dist2[s]=price[s];
edge *l;
int t;
while(!q.empty()){
t=q.front();
q.pop();
inque[t]=0;
l=graph2[t].link;
int maxthis;
while(l){
maxthis=dist2[t]>price[l->d]?dist2[t]:price[l->d];
if(maxthis>dist2[l->d]){
dist2[l->d]=maxthis;if(!inque[l->d]){
q.push(l->d);
inque[l->d]=1;
}
}
l=l->link;
}
}
}int calculate(){
int money[100010];
for(int i=1;i<=n;i++)
money[i]=dist2[i]-dist[i];
int maxx=-9999;
for(int i=1;i<=n;i++)
maxx=maxx>money[i]?maxx:money[i];
if(maxx<0)
maxx=0;return maxx;
}int main(){
#ifdef debug
freopen("in.txt","r",stdin);
#endifbuild();
spfa(1); //正向SPFA
spfa2(n); //反向SPFA
printf("%d",calculate());
return 0;
} -
02015-11-05 14:55:09@
加边的时候存一张反图,从n开始dfs 把所有能够到达n的点打上标记
然后从1开始spfa 用dis[i]表示到达i点之前可能获得的最小价格水晶球 然后SPFA搞一搞
最后扫一遍所有打过标记的点 ans=max(ans,v[i]-dis[i]) (i点可以到达n) 注意不要忘了判断能否到达n表示被坑好多次#include <cstdio>
#include <algorithm>
#include <queue>
using namespace std;
const int N=100010,INF=2099999999;
int e[N*10],pre[N*10],now[N],tail,n,m,x,y,z,v[N],inq[N],dis[N],ans,e2[N*10],pre2[N*10],now2[N],tail2,vis[N];//dis[i]表示到城市i前可以获得的最小价值的水晶球void add(int u,int v){e[++tail]=v;pre[tail]=now[u];now[u]=tail;}
void add2(int u,int v){e2[++tail2]=v;pre2[tail2]=now2[u];now2[u]=tail2;}void dfs(int a){
if(vis[a])return;vis[a]=true;
for(int i=now2[a];i;i=pre2[i]) dfs(e2[i]);
}int main(){
freopen("1754.in","r",stdin);freopen("1754.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&v[i]),dis[i]=INF;
for(int i=1;i<=m;i++) {
scanf("%d%d%d",&x,&y,&z);
if(z==1) add(x,y),add2(y,x);else add(x,y),add2(y,x),add(y,x),add2(x,y);
}
dfs(n);
queue<int> q;
q.push(1);inq[1]=true;dis[1]=v[1];
while(!q.empty()){
int x=q.front();q.pop();inq[x]=false;
for(int i=now[x];i;i=pre[i]){
if(dis[x] < dis[e[i]] || v[e[i]]<dis[e[i]]){
dis[e[i]]=min(dis[e[i]],v[e[i]]);
dis[e[i]]=min(dis[e[i]],dis[x]);
if(!inq[e[i]]) {
q.push(e[i]);inq[e[i]]=true;
}
}
}
}
for(int i=1;i<=n;i++) if(vis[i]) ans=max(ans,v[i]-dis[i]);
printf("%d",ans);
return 0;
} -
02015-10-02 15:31:59@
反向BFS去掉不能到达的点,正向SPFA记录每个点,以这个点为卖出的话,能够买入的最小钱,即来的路上的最小价格。时间是O(n)的
-
02015-09-30 20:53:02@
/*
Author : Slience_K
Belong : C++
Pro : NOIP 2009 - 3*/
#include <cstdio>
#include <vector>
#include <algorithm>
#define sz 100005
using namespace std;
int n , m , u , v , w , ans;
int maxn[ sz ] , minn[ sz ] , p[ sz ];
vector <int> map[ sz ];
vector <int> pic[ sz ];
void Dfs1( int x , int k ){
minn[ x ] = min( minn[ x ] , k );
for( int i = 0 ; i < map[ x ].size() ; i++ ){
int v = map[ x ][ i ];
if ( minn[ v ] > k ) Dfs1( v , min( k , p[ v ] ) );
}
}
void Dfs2( int x , int k ){
maxn[ x ] = max( maxn[ x ] , k );
for( int i = 0 ; i < pic[ x ].size() ; i++ ){
int v = pic[ x ][ i ];
if ( maxn[ v ] < k ) Dfs2( v , max( k , p[ v ] ) );
}
}
int main(){
// freopen( "trade.in" , "r" , stdin );
// freopen( "trade.out" , "w" ,stdout );
scanf( "%d%d" , &n , &m );
for( int i = 1 ; i <= n ; i++ )
scanf( "%d" , &p[ i ] );
for( int i = 1 ; i <= m ; i++ ){
scanf( "%d%d%d" , &u , &v , &w );
map[ u ].push_back( v );
pic[ v ].push_back( u );
if ( w == 2 ){
map[ v ].push_back( u );
pic[ u ].push_back( v );
}
}
for( int i = 1 ; i <= n ; i++ )
maxn[ i ] = -sz , minn[ i ] = sz;
Dfs1( 1 , p[ 1 ] );
Dfs2( n , p[ n ] );
ans = 0;
for( int i = 1 ; i <= n ; i++ )
if (( minn[ i ] != sz )&&( maxn[ i ] != -sz )) ans = max( ans , maxn[ i ] - minn[ i ] );
printf( "%d" , ans );
// fclose( stdin );
// fclose( stdout );
return 0;
} -
02015-09-27 17:28:16@
编译成功
测试数据 #0: Accepted, time = 15 ms, mem = 16416 KiB, score = 10
测试数据 #1: Accepted, time = 0 ms, mem = 16420 KiB, score = 10
测试数据 #2: Accepted, time = 0 ms, mem = 16420 KiB, score = 10
测试数据 #3: Accepted, time = 15 ms, mem = 16428 KiB, score = 10
测试数据 #4: Accepted, time = 15 ms, mem = 16512 KiB, score = 10
测试数据 #5: Accepted, time = 0 ms, mem = 16416 KiB, score = 10
测试数据 #6: Accepted, time = 0 ms, mem = 16420 KiB, score = 10
测试数据 #7: Accepted, time = 15 ms, mem = 16428 KiB, score = 10
测试数据 #8: Accepted, time = 15 ms, mem = 16520 KiB, score = 10
测试数据 #9: Accepted, time = 31 ms, mem = 16496 KiB, score = 10
Accepted, time = 106 ms, mem = 16520 KiB, score = 100spfa维护到i时Min[i]最小值,Ans[i]最大值
-
02015-08-14 21:39:46@
用强联通分量+拓扑排序+dp AC,不过有180行
测试数据 #0: Accepted, time = 0 ms, mem = 4792 KiB, score = 10
测试数据 #1: Accepted, time = 4 ms, mem = 4792 KiB, score = 10
测试数据 #2: Accepted, time = 37 ms, mem = 5260 KiB, score = 10
测试数据 #3: Accepted, time = 515 ms, mem = 14180 KiB, score = 10
测试数据 #4: Accepted, time = 500 ms, mem = 14180 KiB, score = 10
测试数据 #5: Accepted, time = 0 ms, mem = 4828 KiB, score = 10
测试数据 #6: Accepted, time = 65 ms, mem = 5732 KiB, score = 10
测试数据 #7: Accepted, time = 250 ms, mem = 9608 KiB, score = 10
测试数据 #8: Accepted, time = 515 ms, mem = 14664 KiB, score = 10
测试数据 #9: Accepted, time = 468 ms, mem = 14652 KiB, score = 10时间不太好看,主要是因为用了Kosaraju,在数据量大的情况下2遍dfs是很慢的。改成Tarjan应该快很多。
用链表存边,正反向都要。边界点定义:typedef struct _node{
int to;
struct _node* next;
} node;强联通完之后再生成一张新图。由于有正向图、反向图、缩点图共三幅,所以把 添加边 写成了一个函数,以便重用:
void addEdge(node **G, int from, int to){
node p=G[from];
if(from==to) //请注意:缺少这个判断将造成自环,以致后面的入度计算有误。这是50分和100分的差别。
return;
if(G[from]==NULL){
G[from] = (node)malloc(sizeof(node*));
G[from]->to = to;
G[from]->next = NULL;
}else{
while(p->next != NULL){
if(p->to==to)
return;
p = p->next;
}
if(p->to==to)
return;
p->next = (node*)malloc(sizeof(node*));
p = p->next;
p->to = to;
p->next = NULL;
}
}在进行强联通分量求解时,需要对反向dfs增加一些步骤(以在行后注明)。使用Tarjan类同。
void dfsReversed(int indexSCC, int index, int size){ //indexSCC指的是这一个强联通分量在全局中是第几个,由主程序传入
node *p = reversedGraph[index];
if(searched[index])
return;
//price数组存储数据输入的每个城市的物价
value[indexSCC] = MAX(value[indexSCC], price[index]); //更新该强联通分量的最大收益
cost[indexSCC] = MIN(cost[indexSCC], price[index]); //更新该强联通分量的最小消耗
searched[index] = 1;
id[index] = indexSCC;
while(p!=NULL){
dfsReversed(indexSCC, p->to, size);
p = p->next;
}
}生成缩点图并计算入度:
for(i=0; i<numVertex; i++){
p = graph[i];
while(p!=NULL){
addEdge(newGraph, id[i], id[p->to]);
p = p->next;
}
}
for(i=0; i<numSCC; i++){
p = newGraph[i];
while(p!=NULL){
in[p->to]++;
p = p->next;
}
}最后,拓扑排序+动态规划。这里用到了队列以降低复杂度。把每一个入读为零的点加入队列,一直执行直至队列为空。
for(i=0; i<numSCC; i++)
best[i] = value[i]-cost[i]; //先进行预处理,防止孤立的点产生错误
push(id[0]); //push函数将数据加至队尾
while((i = shift())>=0){ //shift函数返回队头
p = newGraph[i];
in[i] = -1;
while(p!=NULL){
in[p->to]--;
if(in[p->to]==0){
in[p->to] = -1;
push(p->to);
}
/*
接下来两行是重点。首先更新一路走来到达p->to点的最小花费。
best[x]记录x点及之前经过的点出售后获利的最大值。
1. 若之前的点已出售,则 best[x] = best[y],其中y是x的前继
2. 若之前的点还未出售,则best[x] = value[x]-cost[x]
综合而言, best[x]为1,2情况的最大值
*/
cost[p->to] = MIN(cost[p->to], cost[i]);
best[p->to] = MAX(best[p->to], MAX(best[i], value[p->to]-cost[p->to]));
p = p->next;
}
} -
02015-08-03 14:57:53@
P1754最优贸易
Accepted记录信息
评测状态 Accepted
题目 P1754 最优贸易
递交时间 2015-08-03 14:57:12
代码语言 C++
评测机 Jtwd2
消耗时间 1040 ms
消耗内存 9580 KiB
评测时间 2015-08-03 14:57:14评测结果
编译成功
foo.cpp: In function 'void dfs(point*, int)':
foo.cpp:36:38: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
foo.cpp: In function 'void dfs2(point*)':
foo.cpp:47:39: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
foo.cpp: In function 'int main()':
foo.cpp:91:41: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]测试数据 #0: Accepted, time = 15 ms, mem = 4784 KiB, score = 10
测试数据 #1: Accepted, time = 15 ms, mem = 4780 KiB, score = 10
测试数据 #2: Accepted, time = 15 ms, mem = 4900 KiB, score = 10
测试数据 #3: Accepted, time = 124 ms, mem = 6608 KiB, score = 10
测试数据 #4: Accepted, time = 202 ms, mem = 8064 KiB, score = 10
测试数据 #5: Accepted, time = 15 ms, mem = 4796 KiB, score = 10
测试数据 #6: Accepted, time = 31 ms, mem = 5020 KiB, score = 10
测试数据 #7: Accepted, time = 93 ms, mem = 6344 KiB, score = 10
测试数据 #8: Accepted, time = 265 ms, mem = 9432 KiB, score = 10
测试数据 #9: Accepted, time = 265 ms, mem = 9580 KiB, score = 10
Accepted, time = 1040 ms, mem = 9580 KiB, score = 100
代码
#include <iostream>
#include <stdio.h>
#include <vector>
#include <algorithm>using namespace std;
int n , m;
int i;
int x , y;
int s;struct point
{
vector < point * > link;
vector < point * > link2;
int inprice;
int outprice;
int visit;
int num;
int reach;
};point line[100000 + 2];
vector < point * > order[100 + 2];void dfs( point * a , int v )
{
if( !a -> reach )
return;
if( a -> visit )
return;
a -> visit = 1;
a -> inprice = v;
int i;
for( i = 0 ; i < a -> link.size() ; i++ )
dfs( a -> link[i] , v );
return;
}void dfs2( point * a )
{
if( a -> reach )
return;
a -> reach = 1;
int i;
for( i = 0 ; i < a -> link2.size() ; i++ )
dfs2( a -> link2[i] );
return;
}int maxd;
int j;int max( int a , int b )
{
if( a > b )
return a;
return b;
}int main()
{
scanf( "%d %d" , &n , &m );
for( i = 1 ; i <= n ; i++ )
{
line[i].num = i;
scanf( "%d" , &line[i].outprice );
line[i].inprice = line[i].outprice;
}
for( i = 0 ; i < m ; i++ )
{
scanf( "%d %d %d" , &x , &y , &s );
if( s == 2 )
{
line[x].link.push_back( &line[y] );
line[y].link.push_back( &line[x] );
line[x].link2.push_back( &line[y] );
line[y].link2.push_back( &line[x] );
}
else
{
line[x].link.push_back( &line[y] );
line[y].link2.push_back( &line[x] );
}
}
for( i = 1 ; i <= n ; i++ )
order[ line[i].outprice ].push_back( &line[i] );
dfs2( &line[n] );
for( i = 1 ; i <= 100 ; i++ )
for( j = 0 ; j < order[i].size() ; j++ )
dfs( order[i][j] , i );
for( i = 1 ; i <= n ; i++ )
maxd = max( maxd , line[i].outprice - line[i].inprice );
cout << maxd << endl;
return 0;
}
读题的重要性! -
02015-06-21 17:31:59@
测试数据 #0: Accepted, time = 0 ms, mem = 5856 KiB, score = 10
测试数据 #1: Accepted, time = 0 ms, mem = 5852 KiB, score = 10
测试数据 #2: Accepted, time = 0 ms, mem = 5848 KiB, score = 10
测试数据 #3: Accepted, time = 46 ms, mem = 5852 KiB, score = 10
测试数据 #4: Accepted, time = 62 ms, mem = 5928 KiB, score = 10
测试数据 #5: Accepted, time = 0 ms, mem = 5852 KiB, score = 10
测试数据 #6: Accepted, time = 15 ms, mem = 5852 KiB, score = 10
测试数据 #7: Accepted, time = 31 ms, mem = 5848 KiB, score = 10
测试数据 #8: Accepted, time = 93 ms, mem = 5944 KiB, score = 10
测试数据 #9: Accepted, time = 78 ms, mem = 5920 KiB, score = 10
Accepted, time = 325 ms, mem = 5944 KiB, score = 100SPFA。
唉...C++党一定要注意用标准输入输出,不然过都过不了...
用数值代替指针的话会快一点。一次SPFA即可。
f[i]:到第i个城市的最大收益。
b[i]:到第i个城市的最小买入价格。每次到达一个城市有三个选择:先前到达时的最大收益、在之前经过的城市卖出获得的收益,在先前某个城市买入、该城市卖出的收益,f[TO[e]]=max(f[TO[e]],f[i],w[TO[e]]-b[i])。
如果收益增加了或者买入价格降低了就进行拓展。
最后f[N]就是最大收益。
参考:http://blog.sina.com.cn/s/blog_8442ec3b0100uosn.html
Block Code
#include<climits>
#include<cstring>
#include<queue>
#include<cstdio>
using namespace std;int N,M;
int NEXT[500003],TO[500003],V=0;
int w[100003],first[100003];
void add_edge(int n,int t)
{
V++;
TO[V]=t;
NEXT[V]=first[n];
first[n]=V;
}int f[MAXN],b[MAXN];
queue<int> q;
bool in[MAXN];int main()
{scanf("%d%d",&N,&M);
for(int i=1;i<=N;i++)
{
scanf("%d",&w[i]);
first[i]=0;
f[i]=INT_MIN;
b[i]=w[i];
}
for(int i=1;i<=M;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
add_edge(x,y);
if(z==2) add_edge(y,x);
}memset(in,false,sizeof(in));
q.push(1);
f[1]=0;
in[1]=true;while(!q.empty())
{
int i=q.front();
q.pop();
in[i]=false;int e=first[i];
while(e!=0)
{
bool flag=false;if(f[TO[e]]<max(f[i],w[TO[e]]-b[i]))
{
f[TO[e]]=max(f[i],w[TO[e]]-b[i]);
flag=true;
}if(b[TO[e]]>b[i])
{
b[TO[e]]=b[i];
flag=true;
}if(flag&&!in[TO[e]])
{
q.push(TO[e]);
in[TO[e]]=true;
}
e=NEXT[e];
}
}printf("%d\n",f[N]);
return 0;
} -
02015-01-28 22:17:34@
严格O(nlogn+m)的算法.三个DFS.
读边的时候记下它的反向边存好.
第一次DFS,从起点开始,记录哪些节点能从起点到达.
第二次DFS,从终点,使用反向边,记录哪些节点能从终点到达.
把城市按照价值升序排序,开一个数组minv记录"对于所有到达此城市的路径,所能得出的最小购买价格".
从价值小的城市开始对每个城市做DFS,遍历它能达到的所有节点,给minv赋值.
很明显节点的minv有值以后就不再对它做DFS.因此,这n此操作复杂度是O(n+m).
最后统计,城市的minv与售价的差值,取最大输出.PS:ORZ SPFA的 强连通分量缩点的 拓扑图DP的 都是些啥
测试数据 #0: Accepted, time = 3 ms, mem = 33976 KiB, score = 10
测试数据 #1: Accepted, time = 15 ms, mem = 33976 KiB, score = 10
测试数据 #2: Accepted, time = 0 ms, mem = 33976 KiB, score = 10
测试数据 #3: Accepted, time = 15 ms, mem = 33984 KiB, score = 10
测试数据 #4: Accepted, time = 19 ms, mem = 33976 KiB, score = 10
测试数据 #5: Accepted, time = 0 ms, mem = 33984 KiB, score = 10
测试数据 #6: Accepted, time = 15 ms, mem = 33984 KiB, score = 10
测试数据 #7: Accepted, time = 31 ms, mem = 34104 KiB, score = 10
测试数据 #8: Accepted, time = 46 ms, mem = 34364 KiB, score = 10
测试数据 #9: Accepted, time = 66 ms, mem = 34364 KiB, score = 10
###Block code
const int INF=(1<<30)-1;
struct edge
{
int in;
edge*nxt;
}pool[4005000];
edge*et=pool;
edge*eds[100050];
edge*edp[100050];
void addedge(int i,int j)
{ et->in=j; et->nxt=eds[i]; eds[i]=et++; }
void addrevedge(int i,int j)
{ et->in=j; et->nxt=edp[i]; edp[i]=et++; }
#define FOREACH_EDGE(i,j) for(edge*i=eds[j];i;i=i->nxt)
#define FOREACH_REV_EDGE(i,j) for(edge*i=edp[j];i;i=i->nxt)int getint()
{
int res=0;
char c=getchar();
while( c<'0' || '9'<c ) c=getchar();
while( '0'<=c && c<='9' )
{ res=res*10+c-'0'; c=getchar(); }
return res;
}int v[100050];
int n,m;int st,ed;
bool rch[100050]; //can this node be reached?
void rchDFS(int x)
{
rch[x]=true;
FOREACH_EDGE(i,x)
if(!rch[i->in]) rchDFS(i->in);
}bool red[100050]; //can we reach terminal from this node?
void redDFS(int x)
{
red[x]=true;
FOREACH_REV_EDGE(i,x)
if(!red[i->in]) redDFS(i->in);
}int p[100050];
bool cmp(int a,int b)
{ return v[a]<v[b]; }int cv;
int minv[100050];
void DFS(int x)
{
minv[x]=cv;
FOREACH_EDGE(i,x)
if(minv[i->in]==INF) DFS(i->in);
}int main()
{
n=getint();
m=getint();
for(int i=0;i<n;i++)
v[i]=getint();
for(int i=0;i<m;i++)
{
int a=getint();
int b=getint();
int c=getint();
a--,b--;
addedge(a,b);
addrevedge(b,a);
if(c==2) addedge(b,a),addrevedge(a,b);
}st=0;
ed=n-1;rchDFS(st);
redDFS(ed);for(int i=0;i<n;i++)
p[i]=i,minv[i]=INF;
sort(p,p+n,cmp);for(int i=0;i<n;i++)
if(rch[p[i]] && minv[p[i]]==INF)
{ cv=v[p[i]]; DFS(p[i]); }int res=0;
for(int i=0;i<n;i++)
if(rch[i] && red[i] && v[i]-minv[i]>res )
res=v[i]-minv[i];printf("%d\n",res);
return 0;
} -
02014-08-08 02:11:19@
上次发的观看效果不太好,竟然不能编辑我自己的帖子,只能重发。
Tarjan强连通分量缩点+拓扑序dp
对缩点后的连通分量维护各分量内最大和最小值
测试数据 #0: Accepted, time = 0 ms, mem = 8788 KiB, score = 10
测试数据 #1: Accepted, time = 0 ms, mem = 8788 KiB, score = 10
测试数据 #2: Accepted, time = 15 ms, mem = 8880 KiB, score = 10
测试数据 #3: Accepted, time = 140 ms, mem = 10316 KiB, score = 10
测试数据 #4: Accepted, time = 171 ms, mem = 11424 KiB, score = 10
测试数据 #5: Accepted, time = 0 ms, mem = 8796 KiB, score = 10
测试数据 #6: Accepted, time = 15 ms, mem = 8932 KiB, score = 10
测试数据 #7: Accepted, time = 46 ms, mem = 9764 KiB, score = 10
测试数据 #8: Accepted, time = 140 ms, mem = 11740 KiB, score = 10
测试数据 #9: Accepted, time = 140 ms, mem = 11720 KiB, score = 10
Accepted, time = 667 ms, mem = 11740 KiB, score = 100
代码如下
###Block code
#include<cstdio>
#include<algorithm>
#include<vector>
#include<utility>
#include<queue>
using namespace std;
#define MAXN 100010
#define MAXM 1000010
#define INF 0x3f3f3f3f
typedef long long LL;
LL dp[MAXN],f[MAXN],a[MAXN],bin[MAXN],sout[MAXN];
int n,m,bcc[MAXN],dfsno,bccno,s[MAXN],stop,dfn[MAXN],low[MAXN],ind[MAXN];
bool ins[MAXN];
vector<vector<int> > adj(MAXN),map(MAXN);
void tarjan(int u) {
dfn[u]=low[u]=++dfsno;
ins[u]=true;
s[stop++]=u;
for(int i=0;i<adj[u].size();i++) {
int v=adj[u][i];
if(dfn[v]==0) {
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(ins[v]) low[u]=min(low[u],dfn[v]);
}
if(low[u]==dfn[u]) {
bccno++;
while(1) {
int p=s[--stop];
ins[p]=false;
bcc[p]=bccno;
bin[bccno]=min(bin[bccno],a[p]);
sout[bccno]=max(sout[bccno],a[p]);
if(p==u) break;
}
}
}
int main() {
fill(bin,bin+MAXN,INF);
int x,y,z;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
for(int i=0;i<m;i++) {
scanf("%d%d%d",&x,&y,&z);
adj[x].push_back(y);
if(z==2) adj[y].push_back(x);
}
tarjan(1);
for(int u=1;u<=n;u++) {
for(int i=0;i<adj[u].size();i++) {
int v=adj[u][i];
if(bcc[u]!=bcc[v]) {
ind[bcc[v]]++;
map[bcc[u]].push_back(bcc[v]);
}
}
}
queue<int> q;
q.push(bcc[1]);
dp[bcc[1]]=0ll;
f[bcc[1]]=bin[bcc[1]];
while(!q.empty()) {
int u=q.front();
q.pop();
for(int i=0;i<map[u].size();i++) {
int v=map[u][i];
f[v]=min(f[u],bin[v]);
dp[v]=max(dp[u],sout[v]-f[v]);
ind[v]--;
if(ind[v]==0) q.push(v);
}
}
printf("%lld\n",dp[bcc[n]]);
return 0;
} -
02014-03-11 22:55:37@
新手也来发个题解……
Tarjan缩强连通分量+拓扑序dp
对缩点后的连通分量保存各分量内最大和最小值测试数据 #0: Accepted, time = 0 ms, mem = 8788 KiB, score = 10
测试数据 #1: Accepted, time = 0 ms, mem = 8788 KiB, score = 10
测试数据 #2: Accepted, time = 15 ms, mem = 8880 KiB, score = 10
测试数据 #3: Accepted, time = 140 ms, mem = 10316 KiB, score = 10
测试数据 #4: Accepted, time = 171 ms, mem = 11424 KiB, score = 10
测试数据 #5: Accepted, time = 0 ms, mem = 8796 KiB, score = 10
测试数据 #6: Accepted, time = 15 ms, mem = 8932 KiB, score = 10
测试数据 #7: Accepted, time = 46 ms, mem = 9764 KiB, score = 10
测试数据 #8: Accepted, time = 140 ms, mem = 11740 KiB, score = 10
测试数据 #9: Accepted, time = 140 ms, mem = 11720 KiB, score = 10
Accepted, time = 667 ms, mem = 11740 KiB, score = 100#include<cstdio>
#include<algorithm>
#include<vector>
#include<utility>
#include<queue>
using namespace std;
#define MAXN 100010
#define MAXM 1000010
#define INF 0x3f3f3f3f
typedef long long LL;
LL dp[MAXN],f[MAXN],a[MAXN],bin[MAXN],sout[MAXN];
int n,m,bcc[MAXN],dfsno,bccno,s[MAXN],stop,dfn[MAXN],low[MAXN],ind[MAXN];
bool ins[MAXN];
vector<vector<int> > adj(MAXN),map(MAXN);
void tarjan(int u) {
dfn[u]=low[u]=++dfsno;
ins[u]=true;
s[stop++]=u;
for(int i=0;i<adj[u].size();i++) {
int v=adj[u][i];
if(dfn[v]==0) {
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(ins[v]) low[u]=min(low[u],dfn[v]);
}
if(low[u]==dfn[u]) {
bccno++;
while(1) {
int p=s[--stop];
ins[p]=false;
bcc[p]=bccno;
bin[bccno]=min(bin[bccno],a[p]);
sout[bccno]=max(sout[bccno],a[p]);
if(p==u) break;
}
}
}
int main() {
fill(bin,bin+MAXN,INF);
int x,y,z;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
for(int i=0;i<m;i++) {
scanf("%d%d%d",&x,&y,&z);
adj[x].push_back(y);
if(z==2) adj[y].push_back(x);
}
tarjan(1);
for(int u=1;u<=n;u++) {
for(int i=0;i<adj[u].size();i++) {
int v=adj[u][i];
if(bcc[u]!=bcc[v]) {
ind[bcc[v]]++;
map[bcc[u]].push_back(bcc[v]);
}
}
}
queue<int> q;
q.push(bcc[1]);
dp[bcc[1]]=0ll;
f[bcc[1]]=bin[bcc[1]];
while(!q.empty()) {
int u=q.front();
q.pop();
for(int i=0;i<map[u].size();i++) {
int v=map[u][i];
f[v]=min(f[u],bin[v]);
dp[v]=max(dp[u],sout[v]-f[v]);
ind[v]--;
if(ind[v]==0) q.push(v);
}
}
printf("%lld\n",dp[bcc[n]]);
return 0;
}