前言
一道既可以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;
}
}
网络流做法
网络流做法题解比较多,在这里就不讲了。