原题链接:https://www.luogu.org/problemnew/show/P2747
据说是IOI 1993?不过既然这道题没有奶牛,所以应该不是USACO原创题。
题意简述:给出n个城市,再给出m条双向边,要求求一条路径,能够从1号城市走到n号城市,再从n号城市返回1号城市,除了1号城市之外,其他城市都只能经过一次。
比较有意思的是关于字符串的处理,普遍都使用了STL,然而作为已经写过AC自动机而且STL非常菜的我,选择了trie树,在end标记上记录城市对应的编号。每次加边的时候查询这条边连接了哪两个城市,然后加到邻接矩阵里即可。
至于DP部分,完全可以转化为从1号城市出发的两条走到n的路径,设f[i][j]为第一条路径走到i,另一条走到j
转移方程:if(e[j][k])f[i][j]=max(f[i][j],f[i][k]+1);
当然,也可以像“最长k可重区间集问题”一样,转化为一个费用流解决。
PS:目前此题拿了luogu的rank3
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; struct tire { int vis[33]; int end; }tr[2005]; char s[55],t[55]; int n,m,cnt,tot; int e[105][105],f[105][105]; void build() { int len=strlen(s); int tx=0; for(int i=0;i<len;i++) { int z; if(s[i]<='Z') z=s[i]-'A'; else z=s[i]-'a'; if(tr[tx].vis[z]==0) tr[tx].vis[z]=++cnt; tx=tr[tx].vis[z]; } tr[tx].end=++tot; } int find(char a[]) { int len=strlen(a); int tx=0; for(int i=0;i<len;i++) { int z; if(a[i]<='Z') z=a[i]-'A'; else z=a[i]-'a'; tx=tr[tx].vis[z]; } return tr[tx].end; } int main() { scanf("%d %d",&n,&m); for(int i=1;i<=n;i++) { scanf("%s",s); build(); } for(int i=1;i<=m;i++) { scanf("%s %s",s,t); int l=find(s); int r=find(t); // printf("%d %d ",l,r); e[l][r]=e[r][l]=1; } memset(f,-63,sizeof(f)); f[1][1]=1; for(int i=1;i<n;i++) { for(int j=i+1;j<=n;j++) { for(int k=1;k<j;k++) { if(e[j][k]) { f[i][j]=max(f[i][j],f[i][k]+1); f[j][i]=f[i][j]; } } } } int ans=1; for(int i=1;i<=n;i++) { if(e[i][n]) ans=max(ans,f[i][n]); } printf("%d",ans); return 0; }
还有一道这道题的改版,其实是网络流24题里的航空路线问题
题目链接:https://www.luogu.org/problemnew/show/P2770
大概就是增加了输出方案的要求,所以要使用网络流。
将每个点看做有流量限制为1,使用最大费用最大流,记录最大流即可。
PS:此题luogu rank2,tires树大法好,比map不知道高到哪里去了。
#include<cstdio> #include<queue> #include<cstring> #include<algorithm> using namespace std; const int inf=(1<<30)-1; void read(int &y) { y=0;char x=getchar(); while(x<'0'||x>'9') x=getchar(); while(x>='0'&&x<='9') { y=y*10+x-'0'; x=getchar(); } } int n,m,tot,num,t; char s[105][105],st[105]; int l,r,sum,cnt=1; int q[205],ans; struct tire { int vis[75],end; }tr[2005]; int getnum(char x) { if(x>='A'&&x<='Z') return x-'A';//0-25 if(x>='a'&&x<='z') return x-'a'+26;//26-51 if(x>='0'&&x<='9') return x-'0'+52;//51-61; } void build(char a[]) { int len=strlen(a),x=0; for(int i=0;i<len;i++) { int tx=getnum(a[i]); if(tr[x].vis[tx]==0) tr[x].vis[tx]=++num; x=tr[x].vis[tx]; } tr[x].end=++tot; } int find(char a[]) { int len=strlen(a),x=0; for(int i=0;i<len;i++) { int tx=getnum(a[i]); x=tr[x].vis[tx]; } return tr[x].end; } struct edge { int u,v,w,c; int frm; }e[20005]; int dis[205],head[205],vis[205]; int fr[205],flow; void add(int u,int v,int w,int c) { e[++cnt].u=head[u];e[cnt].v=v; e[cnt].w=w;e[cnt].c=c; e[cnt].frm=u;head[u]=cnt; e[++cnt].u=head[v];e[cnt].v=u; e[cnt].w=0;e[cnt].c=-c; e[cnt].frm=v;head[v]=cnt; } int spfa() { for(int i=1;i<=t;i++) dis[i]=inf; memset(vis,0,sizeof(vis)); queue<int>q; q.push(1); vis[1]=1;dis[1]=0; while(!q.empty()) { int nxt=q.front();q.pop(); for(int i=head[nxt];i!=-1;i=e[i].u) { int tmp=e[i].v; if(dis[tmp]>dis[nxt]+e[i].c&&e[i].w) { dis[tmp]=dis[nxt]+e[i].c; fr[tmp]=i; if(vis[tmp]==0) { vis[tmp]=1; q.push(tmp); } } } vis[nxt]=0; } if(dis[t]==inf) return 0; return 1; } int mcf() { int re=0,x=inf; for(int i=fr[t];i;i=fr[e[i].frm]) x=min(e[i].w,x); for(int i=fr[t];i;i=fr[e[i].frm]) { e[i].w-=x; e[i^1].w+=x; re+=x*e[i].c; } flow+=x; return re; } void dfs(int x) { q[++sum]=x; for(int i=head[x];i!=-1;i=e[i].u) { if(e[i].w==0&&e[i].c<0) { dfs(e[i].v); e[i].w=1; return; } } } int main() { // freopen("testdata.in","r",stdin); read(n);read(m); t=(n<<1); memset(head,-1,sizeof(head)); for(int i=1;i<=n;i++) { scanf("%s",s[i]); build(s[i]); add(i,i+n,1,-1); } for(int i=1;i<=m;i++) { scanf("%s",st); l=find(st); scanf("%s",st); r=find(st); add(l+n,r,1,-1); } add(1,n+1,1,-1);add(n,n+n,1,-1); while(spfa()) ans+=mcf(); if(flow==0) { printf("No Solution!"); return 0; } else if(flow==1) { printf("2 %s %s %s",s[1],s[n],s[1]); return 0; } printf("%d ",(-ans)/2-1); dfs(1); for(int i=1;i<=sum;i++) { if(q[i]<=n) printf("%s ",s[q[i]]); } sum=0; dfs(1); for(int i=sum-2;i;i--) { if(q[i]<=n) printf("%s ",s[q[i]]); } return 0; }