航空路线【题解】

9 篇文章 0 订阅
4 篇文章 0 订阅

前言

一道既可以dp又可以网络流的题

题面

SOL

dp做法

首先为了保存状态,最容易想到的就是状态压缩,但是数据范围不允许我们压缩,所以就要换思路。最简单的,就会想到,我们并不关心状态是什么,而关心的是状态是否合法。我们只要让当前这个dp是合法的,他的转移是合法的,他的转移又不会影响到他已经合法的状态,那么这样就可以了。
那么dp就要表示出来合法的是哪一段。
我们又发现,状态之所以不合法,就是因为来时的路与去时的路会有相同的城市。这样就不能先dp去时的路再dp来时的路,要一起搞。dp又是逐渐向右走的。相当于选两条互不相交的起点,终点确定的路。所以表示出两条路分别走到哪里,并且分别走到的这两段都没有交集,这个用 dp[i][j] d p [ i ] [ j ] 表示。然后转移出去就用i,j中的一个向外走一步。但是走到的点一定要大于max(i,j),这样才能保证接下来的状态合法

code

#include<bits/stdc++.h>
using namespace std;
template <class T>
inline void read(T&data){
    data=0;
    register char ch=0;
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch<='9'&&ch>='0'){
        data=(data<<3)+(data<<1)+(ch&15);
        ch=getchar();
    }
    return;
}
template <class R>
inline void write(R data){
    if(data>9)write(data/10);
    putchar(data%10+'0');
}
const int _ =501,__ = 400101;
struct zjy {
    int zh,pre1,pre2;
}dp[_][_];

int n,m;
string f1[_];
map<string,int> f2;
int to[__<<1],nxt[__<<1],head[_<<4],cnt;
int stk1[__],top1,stk2[__],top2;
inline void add(register int a,register int b){
    to[++cnt]=b,nxt[cnt]=head[a],head[a]=cnt;
    to[++cnt]=a,nxt[cnt]=head[b],head[b]=cnt;
}
inline zjy mx(register zjy a,register zjy b){
    if(a.zh>b.zh)return a;
    return b;
}
int dfs(register int now1,register int now2){
    if(dp[now1][now2].zh)return dp[now1][now2].zh+1;
    if(now1==now2)return -999;
    if(now1>now2){
        for(register int i=head[now1];i;i=nxt[i]){
            if(to[i]<now1)dp[now1][now2]=mx(dp[now1][now2],(zjy){dfs(to[i],now2),to[i],now2});
        }   
    }
    else {
        for(register int i=head[now2];i;i=nxt[i]){
            if(to[i]<now2)dp[now1][now2]=mx(dp[now1][now2],(zjy){dfs(now1,to[i]),now1,to[i]});
        }
    }
    if(dp[now1][now2].zh==0)return -999;
    return dp[now1][now2].zh+1;
}

int main(){
    ios::sync_with_stdio(0);
    cin>>n>>m;
    for(register int i=1;i<=n;++i){
        cin>>f1[i];
        f2[f1[i]]=i;
    }
    for(register int i=1;i<=m;++i){
        string a,b;
        cin>>a>>b;
        add(f2[a],f2[b]);
    }
    dp[1][1].zh=1;dp[1][1].pre1=0,dp[1][1].pre2=0;
    register int pf=0;
    for(register int i=head[n];i;i=nxt[i]){
        if(to[i]==1)pf=1;
        for(register int j=nxt[i];j;j=nxt[j]){
            if(to[i]==to[j])continue;
            dp[n][n]=mx(dp[n][n],(zjy){dfs(to[i],to[j]),to[i],to[j]});
        }
    }
    if(dp[n][n].zh==0){
        if(pf==1){
            cout<<pf+1<<endl<<f1[1]<<endl<<f1[n]<<endl<<f1[1];
            return 0;
        }
        cout<<"No Solution!"<<endl;return 0;
    }
    cout<<dp[n][n].zh<<endl;
    stk1[++top1] = n,stk2[++top2] = n;
    register int now1 = n,now2 = n;
    while(1){
        if(now1==0||now2==0)break;
        register int now3 = dp[now1][now2].pre1,now4 = dp[now1][now2].pre2;
        if(now3 != now1){
            stk1[++top1]=now3,now1 =now3;
        }
        if(now4!=now2){
            stk2[++top2]=now4,now2 = now4;
        }
        //cout<<now1<<' '<<now2<<endl;
        if(now1==1&&now2==1)break;
    }
    for(register int i=top1;i;i--){
        cout<<f1[stk1[i]]<<endl;
    }
    for(register int i=2;i<=top2;++i){
        cout<<f1[stk2[i]]<<endl;
    }
}

网络流做法

网络流做法题解比较多,在这里就不讲了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值