graph - hzw模拟赛Test13

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);
}

总结:

没有好好挖掘题目性质。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值