graph - hzw模拟赛Test13
Dp
题解:
注意到,如果按照要求走,这个图是没有环的!
然而我一开始并没有注意到这一点(或者是没仔细往下想),去写spfa了。。。
简单说一下我2s+的spfa,就是d[i][j]表示在i这个点,上一条边距离为j的最长路径的边数。注意到一个点均摊只有O(1)个有用状态,因此可以把j表示成能到达i点的第j大的边,另外开一个vector保存具体长度是几。当然d和vis也是vector。然后直接spfa。
Code:
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>
#define MP make_pair
#define D(x) cout<<#x<<" = "<<x<<" "
#define E cout<<endl
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N = 500005;
int n,m; int ans;
vector<int> len[N], d[N];
vector<bool> vis[N];
struct Edge{ int to,nxt,w,id; } e[N<<1];
int head[N],ec;
void add(int a,int b,int w){
ec++; e[ec].to=b; e[ec].w=w; e[ec].nxt=head[a]; head[a]=ec;
}
void spfa(){
queue<pii> q; for(int i=1;i<=n;i++){ q.push(MP(i,0)); vis[i][0]=true; }
while(!q.empty()){
int u=q.front().first, x=q.front().second, pre=len[u][x];
q.pop(); vis[u][x]=false;
// D(u); D(x); D(pre); E;
ans=max(ans,d[u][x]);
for(int i=head[u];i;i=e[i].nxt) if(e[i].w > pre){
int v=e[i].to, y=e[i].id;
// D(v); D(y); E;
if(d[v][y] < d[u][x] + 1){
d[v][y] = d[u][x] + 1;
if(!vis[v][y]){ vis[v][y]=true; q.push(MP(v,y)); }
}
}
}
}
int main(){
freopen("graph.in","r",stdin);
freopen("graph.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) len[i].push_back(0);
int a,b,w;
for(int i=1;i<=m;i++){
scanf("%d%d%d",&a,&b,&w);
add(a,b,w); len[b].push_back(w);
}
for(int i=1;i<=n;i++) sort(len[i].begin(),len[i].end());
for(int i=1;i<=ec;i++){
int v=e[i].to;
e[i].id=lower_bound(len[v].begin(),len[v].end(),e[i].w)-len[v].begin();
}
for(int i=1;i<=n;i++){ vis[i].resize(len[i].size(),false); d[i].resize(len[i].size(),0); }
// for(int i=1;i<=n;i++){
// D(i); E;
// for(int j=1;j<len[i].size();j++){
// printf("%d ",len[i][j]);
// } E;
// }
// for(int i=1;i<=ec;i++){
// D(e[i].to); D(e[i].w); D(e[i].id); E;
// }
spfa(); printf("%d\n",ans);
}
————————————正解————————————
把边从小到大依次加入,f[i]表示当前到达i的最长路径的边数,
f[to]=max(f[to],f[from]+1)
因为是严格大于,所以等于的不能互相转移,因此开一个临时数组g,转移时先更新g,当边权相等的边转移完了在把g赋值给f即可。
Code:
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <stack>
using namespace std;
const int N = 500005;
int n,m,ans,ec;
int f[N],g[N];
stack<int> s;
struct Edge{
int u,v,w;
Edge(){}
Edge(int a,int b,int _w){ u=a; v=b; w=_w; }
bool operator < (const Edge &other) const{
return w < other.w;
}
} e[N];
int main(){
freopen("graph.in","r",stdin);
freopen("graph.out","w",stdout);
scanf("%d%d",&n,&m);
int a,b,w;
for(int i=1;i<=m;i++){
scanf("%d%d%d",&a,&b,&w);
e[++ec]=Edge(a,b,w);
}
sort(e+1,e+1+ec);
for(int i=1;i<=ec+1;i++){
if(e[i].w!=e[i-1].w){
while(!s.empty()){
f[s.top()]=g[s.top()]; s.pop();
}
}
g[e[i].v]=max(g[e[i].v],f[e[i].u]+1);
s.push(e[i].v);
}
for(int i=1;i<=n;i++) ans=max(ans,f[i]);
printf("%d\n",ans);
}
总结:
没有好好挖掘题目性质。